chore: improvements of the sending route generated by the router process

Closes #14636
This commit is contained in:
Sale Djenic 2024-09-13 13:39:12 +02:00 committed by saledjenic
parent 8bc6db5405
commit ad7e2df78a
26 changed files with 564 additions and 619 deletions

View File

@ -6,6 +6,10 @@ type SignalType* {.pure.} = enum
## Wallet Signals ## Wallet Signals
Wallet = "wallet" Wallet = "wallet"
WalletSignTransactions = "wallet.sign.transactions" WalletSignTransactions = "wallet.sign.transactions"
WalletRouterSendingTransactionsStarted = "wallet.router.sending-transactions-started"
WalletRouterSignTransactions = "wallet.router.sign-transactions"
WalletRouterTransactionsSent = "wallet.router.transactions-sent"
WalletTransactionStatusChanged = "wallet.transaction.status-changed"
WalletSuggestedRoutes = "wallet.suggested.routes" WalletSuggestedRoutes = "wallet.suggested.routes"
NodeReady = "node.ready" NodeReady = "node.ready"
NodeCrashed = "node.crashed" NodeCrashed = "node.crashed"

View File

@ -4,6 +4,7 @@ import base
import signal_type import signal_type
import app_service/service/transaction/dtoV2 import app_service/service/transaction/dtoV2
import app_service/service/transaction/router_transactions_dto
const SignTransactionsEventType* = "sing-transactions" const SignTransactionsEventType* = "sing-transactions"
@ -25,6 +26,10 @@ type WalletSignal* = ref object of Signal
error*: string error*: string
errorCode*: string errorCode*: string
updatedPrices*: Table[string, float64] updatedPrices*: Table[string, float64]
routerTransactionsSendingDetails*: SendDetailsDto
routerTransactionsForSigning*: RouterTransactionsForSigningDto
routerSentTransactions*: RouterSentTransactionsDto
transactionStatusChange*: TransactionStatusChange
proc fromEvent*(T: type WalletSignal, signalType: SignalType, jsonSignal: JsonNode): WalletSignal = proc fromEvent*(T: type WalletSignal, signalType: SignalType, jsonSignal: JsonNode): WalletSignal =
result = WalletSignal() result = WalletSignal()
@ -54,6 +59,24 @@ proc fromEvent*(T: type WalletSignal, signalType: SignalType, jsonSignal: JsonNo
for tx in event: for tx in event:
result.txHashes.add(tx.getStr) result.txHashes.add(tx.getStr)
return return
if signalType == SignalType.WalletRouterSignTransactions:
if event.kind != JObject:
return
result.routerTransactionsForSigning = toRouterTransactionsForSigningDto(event)
return
if signalType == SignalType.WalletRouterTransactionsSent:
if event.kind != JObject:
return
result.routerSentTransactions = toRouterSentTransactionsDto(event)
return
if signalType == SignalType.WalletRouterSendingTransactionsStarted:
result.routerTransactionsSendingDetails = toSendDetailsDto(event)
return
if signalType == SignalType.WalletTransactionStatusChanged:
if event.kind != JObject:
return
result.transactionStatusChange = toTransactionStatusChange(event)
return
if signalType == SignalType.WalletSuggestedRoutes: if signalType == SignalType.WalletSuggestedRoutes:
try: try:
if event.contains("Uuid"): if event.contains("Uuid"):

View File

@ -81,8 +81,12 @@ QtObject:
of SignalType.WhisperFilterAdded: WhisperFilterSignal.fromEvent(jsonSignal) of SignalType.WhisperFilterAdded: WhisperFilterSignal.fromEvent(jsonSignal)
of SignalType.Wallet, of SignalType.Wallet,
SignalType.WalletSignTransactions, SignalType.WalletSignTransactions,
SignalType.WalletRouterSendingTransactionsStarted,
SignalType.WalletRouterSignTransactions,
SignalType.WalletRouterTransactionsSent,
SignalType.WalletTransactionStatusChanged,
SignalType.WalletSuggestedRoutes: SignalType.WalletSuggestedRoutes:
WalletSignal.fromEvent(signalType, jsonSignal) WalletSignal.fromEvent(signalType, jsonSignal)
of SignalType.NodeReady, of SignalType.NodeReady,
SignalType.NodeCrashed, SignalType.NodeCrashed,
SignalType.NodeStarted, SignalType.NodeStarted,

View File

@ -1,5 +1,5 @@
import Tables import Tables
import uuids, chronicles, options import uuids, chronicles
import io_interface import io_interface
import app_service/service/wallet_account/service as wallet_account_service import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/network/service as network_service import app_service/service/network/service as network_service
@ -13,7 +13,6 @@ import app/modules/shared_modules/keycard_popup/io_interface as keycard_shared_m
import app/modules/shared/wallet_utils import app/modules/shared/wallet_utils
import app/modules/shared_models/currency_amount import app/modules/shared_models/currency_amount
import app/core/signals/types
import app/core/eventemitter import app/core/eventemitter
logScope: logScope:
@ -56,11 +55,11 @@ proc delete*(self: Controller) =
proc init*(self: Controller) = proc init*(self: Controller) =
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args): self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
let args = TransactionSentArgs(e) let args = TransactionSentArgs(e)
self.delegate.transactionWasSent(args.chainId, args.txHash, args.uuid, args.error) self.delegate.transactionWasSent(args.uuid, args.chainId, args.approvalTx, args.txHash, args.error)
self.events.on(SIGNAL_OWNER_TOKEN_SENT) do(e:Args): self.events.on(SIGNAL_OWNER_TOKEN_SENT) do(e:Args):
let args = OwnerTokenSentArgs(e) let args = OwnerTokenSentArgs(e)
self.delegate.transactionWasSent(args.chainId, args.txHash, args.uuid, "") self.delegate.transactionWasSent(args.uuid, args.chainId, approvalTx = false, args.txHash, error = "")
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args): self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
let args = SharedKeycarModuleArgs(e) let args = SharedKeycarModuleArgs(e)
@ -72,13 +71,13 @@ proc init*(self: Controller) =
let args = SuggestedRoutesArgs(e) let args = SuggestedRoutesArgs(e)
self.delegate.suggestedRoutesReady(args.uuid, args.suggestedRoutes, args.errCode, args.errDescription) self.delegate.suggestedRoutesReady(args.uuid, args.suggestedRoutes, args.errCode, args.errDescription)
self.events.on(SignalType.WalletSignTransactions.event) do(e:Args): self.events.on(SIGNAL_SIGN_ROUTER_TRANSACTIONS) do(e:Args):
var data = WalletSignal(e) var data = RouterTransactionsForSigningArgs(e)
self.delegate.prepareSignaturesForTransactions(data.txHashes) self.delegate.prepareSignaturesForTransactions(data.data)
self.events.on(SIGNAL_TRANSACTION_SENDING_COMPLETE) do(e:Args): self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionMinedArgs(e) let args = TransactionStatusArgs(e)
self.delegate.transactionSendingComplete(args.transactionHash, args.success) self.delegate.transactionSendingComplete(args.data.hash, args.data.status)
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] = proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
return self.walletAccountService.getWalletAccounts() return self.walletAccountService.getWalletAccounts()
@ -115,6 +114,7 @@ proc suggestedRoutes*(self: Controller,
accountFrom: string, accountFrom: string,
accountTo: string, accountTo: string,
token: string, token: string,
tokenIsOwnerToken: bool,
amountIn: string, amountIn: string,
toToken: string = "", toToken: string = "",
amountOut: string = "", amountOut: string = "",
@ -122,23 +122,20 @@ proc suggestedRoutes*(self: Controller,
disabledToChainIDs: seq[int] = @[], disabledToChainIDs: seq[int] = @[],
lockedInAmounts: Table[string, string] = initTable[string, string](), lockedInAmounts: Table[string, string] = initTable[string, string](),
extraParamsTable: Table[string, string] = initTable[string, string]()) = extraParamsTable: Table[string, string] = initTable[string, string]()) =
self.transactionService.suggestedRoutes(uuid, sendType, accountFrom, accountTo, token, amountIn, toToken, amountOut, self.transactionService.suggestedRoutes(uuid, sendType, accountFrom, accountTo, token, tokenIsOwnerToken, amountIn, toToken, amountOut,
disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable) disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable)
proc stopSuggestedRoutesAsyncCalculation*(self: Controller) = proc stopSuggestedRoutesAsyncCalculation*(self: Controller) =
self.transactionService.stopSuggestedRoutesAsyncCalculation() self.transactionService.stopSuggestedRoutesAsyncCalculation()
proc transfer*(self: Controller, from_addr: string, to_addr: string, assetKey: string, toAssetKey: string, proc buildTransactionsFromRoute*(self: Controller, uuid: string, slippagePercentage: float): string =
uuid: string, selectedRoutes: seq[TransactionPathDto], password: string, sendType: SendType, return self.transactionService.buildTransactionsFromRoute(uuid, slippagePercentage)
usePassword: bool, doHashing: bool, tokenName: string, isOwnerToken: bool,
slippagePercentage: Option[float]) =
self.transactionService.transfer(from_addr, to_addr, assetKey, toAssetKey, uuid, selectedRoutes, password, sendType,
usePassword, doHashing, tokenName, isOwnerToken, slippagePercentage)
proc proceedWithTransactionsSignatures*(self: Controller, fromAddr: string, toAddr: string, proc signMessage*(self: Controller, address: string, hashedPassword: string, hashedMessage: string): tuple[res: string, err: string] =
fromTokenKey: string, toTokenKey: string, uuid: string, signatures: TransactionsSignatures, return self.transactionService.signMessage(address, hashedPassword, hashedMessage)
selectedRoutes: seq[TransactionPathDto], sendType: SendType) =
self.transactionService.proceedWithTransactionsSignatures(fromAddr, toAddr, fromTokenKey, toTokenKey, uuid, signatures, selectedRoutes, sendType) proc sendRouterTransactionsWithSignatures*(self: Controller, uuid: string, signatures: TransactionsSignatures): string =
return self.transactionService.sendRouterTransactionsWithSignatures(uuid, signatures)
proc areTestNetworksEnabled*(self: Controller): bool = proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled() return self.walletAccountService.areTestNetworksEnabled()
@ -159,7 +156,7 @@ proc connectKeycardReponseSignal(self: Controller) =
let currentFlow = self.keycardService.getCurrentFlow() let currentFlow = self.keycardService.getCurrentFlow()
if currentFlow != KCSFlowType.Sign: if currentFlow != KCSFlowType.Sign:
error "trying to use keycard in the other than the signing a transaction flow" error "trying to use keycard in the other than the signing a transaction flow"
self.delegate.transactionWasSent() self.delegate.transactionWasSent(uuid = "", chainId = 0, approvalTx = false, txHash = "", error = "trying to use keycard in the other than the signing a transaction flow")
return return
self.delegate.onTransactionSigned(args.flowType, args.flowEvent) self.delegate.onTransactionSigned(args.flowType, args.flowEvent)
@ -172,4 +169,4 @@ proc runSignFlow*(self: Controller, pin, bip44Path, txHash: string) =
self.keycardService.startSignFlow(bip44Path, txHash, pin) self.keycardService.startSignFlow(bip44Path, txHash, pin)
proc getChainsWithNoGasFromError*(self: Controller, errCode: string, errDescription: string): Table[int, string] = proc getChainsWithNoGasFromError*(self: Controller, errCode: string, errDescription: string): Table[int, string] =
return self.walletAccountService.getChainsWithNoGasFromError(errCode, errDescription) return self.walletAccountService.getChainsWithNoGasFromError(errCode, errDescription)

View File

@ -1,6 +1,7 @@
import Tables, options import Tables
import app/modules/shared_models/currency_amount import app/modules/shared_models/currency_amount
import app_service/service/transaction/dto import app_service/service/transaction/dto
import app_service/service/transaction/router_transactions_dto
import app_service/service/network/network_item import app_service/service/network/network_item
import app/modules/shared_models/collectibles_model as collectibles import app/modules/shared_models/collectibles_model as collectibles
from app_service/service/keycard/service import KeycardEvent from app_service/service/keycard/service import KeycardEvent
@ -27,6 +28,7 @@ method suggestedRoutes*(self: AccessInterface,
accountFrom: string, accountFrom: string,
accountTo: string, accountTo: string,
token: string, token: string,
tokenIsOwnerToken: bool,
amountIn: string, amountIn: string,
toToken: string = "", toToken: string = "",
amountOut: string = "", amountOut: string = "",
@ -42,19 +44,13 @@ method stopUpdatesForSuggestedRoute*(self: AccessInterface) {.base.} =
method suggestedRoutesReady*(self: AccessInterface, uuid: string, suggestedRoutes: SuggestedRoutesDto, errCode: string, errDescription: string) {.base.} = method suggestedRoutesReady*(self: AccessInterface, uuid: string, suggestedRoutes: SuggestedRoutesDto, errCode: string, errDescription: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method authenticateAndTransfer*(self: AccessInterface, from_addr: string, to_addr: string, assetKey: string, method authenticateAndTransferV2*(self: AccessInterface, fromAddr: string, uuid: string, slippagePercentage: float) {.base.} =
toAssetKey: string, uuid: string, sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool) {.base.} =
raise newException(ValueError, "No implementation available")
method authenticateAndTransferWithPaths*(self: AccessInterface, from_addr: string, to_addr: string, assetKey: string,
toAssetKey: string, uuid: string, sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool, rawPaths: string,
slippagePercentage: Option[float]) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string, pin: string) {.base.} = method onUserAuthenticated*(self: AccessInterface, password: string, pin: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method transactionWasSent*(self: AccessInterface, chainId: int = 0, txHash, uuid, error: string = "") {.base.} = method transactionWasSent*(self: AccessInterface, uuid: string, chainId: int = 0, approvalTx: bool = false, txHash: string = "", error: string = "") {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method viewDidLoad*(self: AccessInterface) {.base.} = method viewDidLoad*(self: AccessInterface) {.base.} =
@ -78,7 +74,7 @@ method getCollectiblesModel*(self: AccessInterface): collectibles.Model {.base.}
method splitAndFormatAddressPrefix*(self: AccessInterface, text : string, updateInStore: bool): string {.base.} = method splitAndFormatAddressPrefix*(self: AccessInterface, text : string, updateInStore: bool): string {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method prepareSignaturesForTransactions*(self: AccessInterface, txHashes: seq[string]) {.base.} = method prepareSignaturesForTransactions*(self:AccessInterface, txForSigning: RouterTransactionsForSigningDto) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method onTransactionSigned*(self: AccessInterface, keycardFlowType: string, keycardEvent: KeycardEvent) {.base.} = method onTransactionSigned*(self: AccessInterface, keycardFlowType: string, keycardEvent: KeycardEvent) {.base.} =
@ -87,7 +83,7 @@ method onTransactionSigned*(self: AccessInterface, keycardFlowType: string, keyc
method hasGas*(self: AccessInterface, accountAddress: string, chainId: int, nativeGasSymbol: string, requiredGas: float): bool {.base.} = method hasGas*(self: AccessInterface, accountAddress: string, chainId: int, nativeGasSymbol: string, requiredGas: float): bool {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method transactionSendingComplete*(self: AccessInterface, txHash: string, success: bool) {.base.} = method transactionSendingComplete*(self: AccessInterface, txHash: string, status: string) {.base.} =
raise newException(ValueError, "No implementation available") raise newException(ValueError, "No implementation available")
method getNetworkItem*(self: AccessInterface, chainId: int): NetworkItem {.base.} = method getNetworkItem*(self: AccessInterface, chainId: int): NetworkItem {.base.} =

View File

@ -1,9 +1,12 @@
import tables, NimQml, sequtils, sugar, stint, strutils, chronicles, options import tables, NimQml, sequtils, sugar, stint, strutils, chronicles
import ./io_interface, ./view, ./controller, ./network_route_item, ./transaction_routes, ./suggested_route_item, ./suggested_route_model, ./gas_estimate_item, ./gas_fees_item, ./network_route_model import ./io_interface, ./view, ./controller, ./network_route_item, ./transaction_routes, ./suggested_route_item, ./suggested_route_model, ./gas_estimate_item, ./gas_fees_item, ./network_route_model
import ../io_interface as delegate_interface import ../io_interface as delegate_interface
import app/global/global_singleton import app/global/global_singleton
import app/global/utils
import app/core/eventemitter import app/core/eventemitter
import app_service/common/utils
import app_service/common/wallet_constants
import app_service/service/wallet_account/service as wallet_account_service import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/network/service as network_service import app_service/service/network/service as network_service
import app_service/service/currency/service as currency_service import app_service/service/currency/service as currency_service
@ -11,8 +14,6 @@ import app_service/service/transaction/service as transaction_service
import app_service/service/keycard/service as keycard_service import app_service/service/keycard/service as keycard_service
import app_service/service/keycard/constants as keycard_constants import app_service/service/keycard/constants as keycard_constants
import app_service/service/transaction/dto import app_service/service/transaction/dto
import app_service/service/transaction/dtoV2
import app_service/service/transaction/dto_conversion
import app/modules/shared_models/currency_amount import app/modules/shared_models/currency_amount
import app_service/service/network/network_item as network_service_item import app_service/service/network/network_item as network_service_item
@ -36,7 +37,7 @@ type TmpSendTransactionDetails = object
resolvedSignatures: TransactionsSignatures resolvedSignatures: TransactionsSignatures
tokenName: string tokenName: string
isOwnerToken: bool isOwnerToken: bool
slippagePercentage: Option[float] slippagePercentage: float
type type
Module* = ref object of io_interface.AccessInterface Module* = ref object of io_interface.AccessInterface
@ -48,6 +49,7 @@ type
moduleLoaded: bool moduleLoaded: bool
tmpSendTransactionDetails: TmpSendTransactionDetails tmpSendTransactionDetails: TmpSendTransactionDetails
tmpPin: string tmpPin: string
tmpPassword: string
tmpTxHashBeingProcessed: string tmpTxHashBeingProcessed: string
# Forward declaration # Forward declaration
@ -77,6 +79,13 @@ method delete*(self: Module) =
self.view.delete self.view.delete
self.controller.delete self.controller.delete
proc clearTmpData(self: Module) =
self.tmpPin = ""
self.tmpPassword = ""
self.tmpTxHashBeingProcessed = ""
self.tmpSendTransactionDetails = TmpSendTransactionDetails()
writeStackTrace()
proc convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): NetworkRouteItem = proc convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): NetworkRouteItem =
result = initNetworkRouteItem( result = initNetworkRouteItem(
network.chainId, network.chainId,
@ -174,18 +183,10 @@ method getNetworkItem*(self: Module, chainId: int): network_service_item.Network
return nil return nil
return networks[0] return networks[0]
method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string, assetKey: string, toAssetKey: string, uuid: string, method authenticateAndTransferV2*(self: Module, fromAddr: string, uuid: string, slippagePercentage: float) =
sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool) =
self.tmpSendTransactionDetails.fromAddr = fromAddr
self.tmpSendTransactionDetails.toAddr = toAddr
self.tmpSendTransactionDetails.assetKey = assetKey
self.tmpSendTransactionDetails.toAssetKey = toAssetKey
self.tmpSendTransactionDetails.uuid = uuid self.tmpSendTransactionDetails.uuid = uuid
self.tmpSendTransactionDetails.sendType = sendType self.tmpSendTransactionDetails.slippagePercentage = slippagePercentage
self.tmpSendTransactionDetails.fromAddrPath = ""
self.tmpSendTransactionDetails.resolvedSignatures.clear() self.tmpSendTransactionDetails.resolvedSignatures.clear()
self.tmpSendTransactionDetails.tokenName = selectedTokenName
self.tmpSendTransactionDetails.isOwnerToken = selectedTokenIsOwnerToken
let kp = self.controller.getKeypairByAccountAddress(fromAddr) let kp = self.controller.getKeypairByAccountAddress(fromAddr)
if kp.migratedToKeycard(): if kp.migratedToKeycard():
@ -193,34 +194,36 @@ method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string,
if accounts.len != 1: if accounts.len != 1:
error "cannot resolve selected account to send from among known keypair accounts" error "cannot resolve selected account to send from among known keypair accounts"
return return
self.tmpSendTransactionDetails.fromAddrPath = accounts[0].path
self.controller.authenticate(kp.keyUid) self.controller.authenticate(kp.keyUid)
else: else:
self.controller.authenticate() self.controller.authenticate()
method authenticateAndTransferWithPaths*(self: Module, fromAddr: string, toAddr: string, assetKey: string, toAssetKey: string, uuid: string,
sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool, rawPaths: string, slippagePercentage: Option[float]) =
# Temporary until transaction service rework is completed
let pathsV2 = rawPaths.toTransactionPathsDtoV2()
let pathsV1 = pathsV2.convertToOldRoute().addFirstSimpleBridgeTxFlag()
self.tmpSendTransactionDetails.paths = pathsV1
self.tmpSendTransactionDetails.slippagePercentage = slippagePercentage
self.authenticateAndTransfer(fromAddr, toAddr, assetKey, toAssetKey, uuid, sendType, selectedTokenName, selectedTokenIsOwnerToken)
method onUserAuthenticated*(self: Module, password: string, pin: string) = method onUserAuthenticated*(self: Module, password: string, pin: string) =
if password.len == 0: if password.len == 0:
self.transactionWasSent(chainId = 0, txHash = "", uuid = self.tmpSendTransactionDetails.uuid, error = authenticationCanceled) self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = authenticationCanceled)
self.clearTmpData()
else: else:
self.tmpPin = pin self.tmpPin = pin
let doHashing = self.tmpPin.len == 0 self.tmpPassword = password
let usePassword = self.tmpSendTransactionDetails.fromAddrPath.len == 0 let err = self.controller.buildTransactionsFromRoute(self.tmpSendTransactionDetails.uuid, self.tmpSendTransactionDetails.slippagePercentage)
self.controller.transfer( if err.len > 0:
self.tmpSendTransactionDetails.fromAddr, self.tmpSendTransactionDetails.toAddr, self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = err)
self.tmpSendTransactionDetails.assetKey, self.tmpSendTransactionDetails.toAssetKey, self.tmpSendTransactionDetails.uuid, self.clearTmpData()
self.tmpSendTransactionDetails.paths, password, self.tmpSendTransactionDetails.sendType, usePassword, doHashing,
self.tmpSendTransactionDetails.tokenName, self.tmpSendTransactionDetails.isOwnerToken, self.tmpSendTransactionDetails.slippagePercentage proc sendSignedTransactions*(self: Module) =
) try:
# check if all transactions are signed
for _, (r, s, v) in self.tmpSendTransactionDetails.resolvedSignatures.pairs:
if r.len == 0 or s.len == 0 or v.len == 0:
raise newException(CatchableError, "not all transactions are signed")
let err = self.controller.sendRouterTransactionsWithSignatures(self.tmpSendTransactionDetails.uuid, self.tmpSendTransactionDetails.resolvedSignatures)
if err.len > 0:
raise newException(CatchableError, "sending transaction failed: " & err)
except Exception as e:
error "sendSignedTransactions failed: ", msg=e.msg
self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = e.msg)
self.clearTmpData()
proc signOnKeycard(self: Module) = proc signOnKeycard(self: Module) =
self.tmpTxHashBeingProcessed = "" self.tmpTxHashBeingProcessed = ""
@ -234,35 +237,70 @@ proc signOnKeycard(self: Module) =
self.controller.runSignFlow(self.tmpPin, self.tmpSendTransactionDetails.fromAddrPath, txForKcFlow) self.controller.runSignFlow(self.tmpPin, self.tmpSendTransactionDetails.fromAddrPath, txForKcFlow)
break break
if self.tmpTxHashBeingProcessed.len == 0: if self.tmpTxHashBeingProcessed.len == 0:
self.controller.proceedWithTransactionsSignatures(self.tmpSendTransactionDetails.fromAddr, self.tmpSendTransactionDetails.toAddr, self.sendSignedTransactions()
self.tmpSendTransactionDetails.assetKey, self.tmpSendTransactionDetails.toAssetKey, self.tmpSendTransactionDetails.uuid, self.clearTmpData()
self.tmpSendTransactionDetails.resolvedSignatures, self.tmpSendTransactionDetails.paths, self.tmpSendTransactionDetails.sendType)
method prepareSignaturesForTransactions*(self: Module, txHashes: seq[string]) = proc getRSVFromSignature(self: Module, signature: string): (string, string, string) =
if txHashes.len == 0: let finalSignature = singletonInstance.utils.removeHexPrefix(signature)
error "no transaction hashes to be signed" if finalSignature.len != SIGNATURE_LEN:
return return ("", "", "")
for h in txHashes: let r = finalSignature[0..63]
self.tmpSendTransactionDetails.resolvedSignatures[h] = ("", "", "") let s = finalSignature[64..127]
self.signOnKeycard() let v = finalSignature[128..129]
return (r, s, v)
method prepareSignaturesForTransactions*(self:Module, txForSigning: RouterTransactionsForSigningDto) =
var res = ""
try:
if txForSigning.sendDetails.uuid != self.tmpSendTransactionDetails.uuid:
raise newException(CatchableError, "preparing signatures for transactions are not matching the initial request")
if txForSigning.signingDetails.hashes.len == 0:
raise newException(CatchableError, "no transaction hashes to be signed")
if txForSigning.signingDetails.keyUid == "" or txForSigning.signingDetails.address == "" or txForSigning.signingDetails.addressPath == "":
raise newException(CatchableError, "preparing signatures for transactions failed")
if txForSigning.signingDetails.signOnKeycard:
self.tmpSendTransactionDetails.fromAddrPath = txForSigning.signingDetails.addressPath
for h in txForSigning.signingDetails.hashes:
self.tmpSendTransactionDetails.resolvedSignatures[h] = ("", "", "")
self.signOnKeycard()
else:
let finalPassword = hashPassword(self.tmpPassword)
for h in txForSigning.signingDetails.hashes:
self.tmpSendTransactionDetails.resolvedSignatures[h] = ("", "", "")
var
signature = ""
err: string
(signature, err) = self.controller.signMessage(txForSigning.signingDetails.address, finalPassword, h)
if err.len > 0:
raise newException(CatchableError, "signing transaction failed: " & err)
self.tmpSendTransactionDetails.resolvedSignatures[h] = self.getRSVFromSignature(signature)
self.sendSignedTransactions()
except Exception as e:
error "signMessageWithCallback failed: ", msg=e.msg
self.transactionWasSent(uuid = txForSigning.sendDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = e.msg)
self.clearTmpData()
method onTransactionSigned*(self: Module, keycardFlowType: string, keycardEvent: KeycardEvent) = method onTransactionSigned*(self: Module, keycardFlowType: string, keycardEvent: KeycardEvent) =
if keycardFlowType != keycard_constants.ResponseTypeValueKeycardFlowResult: if keycardFlowType != keycard_constants.ResponseTypeValueKeycardFlowResult:
error "unexpected error while keycard signing transaction" let err = "unexpected error while keycard signing transaction"
error "error", err=err
self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = err)
self.clearTmpData()
return return
self.tmpSendTransactionDetails.resolvedSignatures[self.tmpTxHashBeingProcessed] = (keycardEvent.txSignature.r, self.tmpSendTransactionDetails.resolvedSignatures[self.tmpTxHashBeingProcessed] = (keycardEvent.txSignature.r,
keycardEvent.txSignature.s, keycardEvent.txSignature.v) keycardEvent.txSignature.s, keycardEvent.txSignature.v)
self.signOnKeycard() self.signOnKeycard()
method transactionWasSent*(self: Module, chainId: int, txHash, uuid, error: string) = method transactionWasSent*(self: Module, uuid: string, chainId: int = 0, approvalTx: bool = false, txHash: string = "", error: string = "") =
if txHash.len == 0: if txHash.len == 0:
self.view.sendTransactionSentSignal(chainId = 0, txHash = "", uuid = self.tmpSendTransactionDetails.uuid, error) self.view.sendTransactionSentSignal(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error)
return return
self.view.sendTransactionSentSignal(chainId, txHash, uuid, error) self.view.sendTransactionSentSignal(uuid, chainId, approvalTx, txHash, error)
method suggestedRoutesReady*(self: Module, uuid: string, suggestedRoutes: SuggestedRoutesDto, errCode: string, errDescription: string) = method suggestedRoutesReady*(self: Module, uuid: string, suggestedRoutes: SuggestedRoutesDto, errCode: string, errDescription: string) =
self.tmpSendTransactionDetails.paths = suggestedRoutes.best self.tmpSendTransactionDetails.paths = suggestedRoutes.best
self.tmpSendTransactionDetails.slippagePercentage = none(float) self.tmpSendTransactionDetails.slippagePercentage = 0
let paths = suggestedRoutes.best.map(x => self.convertTransactionPathDtoToSuggestedRouteItem(x)) let paths = suggestedRoutes.best.map(x => self.convertTransactionPathDtoToSuggestedRouteItem(x))
let suggestedRouteModel = newSuggestedRouteModel() let suggestedRouteModel = newSuggestedRouteModel()
suggestedRouteModel.setItems(paths) suggestedRouteModel.setItems(paths)
@ -286,6 +324,7 @@ method suggestedRoutes*(self: Module,
accountFrom: string, accountFrom: string,
accountTo: string, accountTo: string,
token: string, token: string,
tokenIsOwnerToken: bool,
amountIn: string, amountIn: string,
toToken: string = "", toToken: string = "",
amountOut: string = "", amountOut: string = "",
@ -299,6 +338,7 @@ method suggestedRoutes*(self: Module,
accountFrom, accountFrom,
accountTo, accountTo,
token, token,
tokenIsOwnerToken,
amountIn, amountIn,
toToken, toToken,
amountOut, amountOut,
@ -362,5 +402,5 @@ method splitAndFormatAddressPrefix*(self: Module, text : string, updateInStore:
editedText = "<a><p>" & editedText & "</a></p>" editedText = "<a><p>" & editedText & "</a></p>"
return editedText return editedText
method transactionSendingComplete*(self: Module, txHash: string, success: bool) = method transactionSendingComplete*(self: Module, txHash: string, status: string) =
self.view.sendtransactionSendingCompleteSignal(txHash, success) self.view.sendtransactionSendingCompleteSignal(txHash, status)

View File

@ -1,5 +1,4 @@
import NimQml, Tables, json, sequtils, strutils, stint, options, chronicles import NimQml, Tables, json, sequtils, strutils, stint, chronicles
import uuids
import ./io_interface, ./network_route_model, ./network_route_item, ./suggested_route_item, ./transaction_routes import ./io_interface, ./network_route_model, ./network_route_item, ./suggested_route_item, ./transaction_routes
import app_service/service/network/service as network_service import app_service/service/network/service as network_service
@ -165,9 +164,9 @@ QtObject:
self.fromNetworksRouteModel.setItems(fromNetworks) self.fromNetworksRouteModel.setItems(fromNetworks)
self.toNetworksRouteModel.setItems(toNetworks) self.toNetworksRouteModel.setItems(toNetworks)
proc transactionSent*(self: View, chainId: int, txHash: string, uuid: string, error: string) {.signal.} proc transactionSent*(self: View, uuid: string, chainId: int, approvalTx: bool, txHash: string, error: string) {.signal.}
proc sendTransactionSentSignal*(self: View, chainId: int, txHash: string, uuid: string, error: string) = proc sendTransactionSentSignal*(self: View, uuid: string, chainId: int, approvalTx: bool, txHash: string, error: string) =
self.transactionSent(chainId, txHash, uuid, error) self.transactionSent(uuid, chainId, approvalTx, txHash, error)
proc parseChainIds(chainIds: string): seq[int] = proc parseChainIds(chainIds: string): seq[int] =
var parsedChainIds: seq[int] = @[] var parsedChainIds: seq[int] = @[]
@ -175,9 +174,13 @@ QtObject:
parsedChainIds.add(chainId.parseInt()) parsedChainIds.add(chainId.parseInt())
return parsedChainIds return parsedChainIds
proc authenticateAndTransfer*(self: View, uuid: string) {.slot.} = proc authenticateAndTransfer*(self: View, uuid: string, slippagePercentageString: string) {.slot.} =
self.delegate.authenticateAndTransfer(self.selectedSenderAccountAddress, self.selectedRecipient, self.selectedAssetKey, var slippagePercentage: float
self.selectedToAssetKey, uuid, self.sendType, self.selectedTokenName, self.selectedTokenIsOwnerToken) try:
slippagePercentage = slippagePercentageString.parseFloat()
except:
error "parsing slippage failed", slippage=slippagePercentageString
self.delegate.authenticateAndTransferV2(self.selectedSenderAccountAddress, uuid, slippagePercentage)
proc suggestedRoutesReady*(self: View, suggestedRoutes: QVariant, errCode: string, errDescription: string) {.signal.} proc suggestedRoutesReady*(self: View, suggestedRoutes: QVariant, errCode: string, errDescription: string) {.signal.}
proc setTransactionRoute*(self: View, routes: TransactionRoutes, errCode: string, errDescription: string) = proc setTransactionRoute*(self: View, routes: TransactionRoutes, errCode: string, errDescription: string) =
@ -186,7 +189,7 @@ QtObject:
self.errDescription = errDescription self.errDescription = errDescription
self.suggestedRoutesReady(newQVariant(self.transactionRoutes), errCode, errDescription) self.suggestedRoutesReady(newQVariant(self.transactionRoutes), errCode, errDescription)
proc suggestedRoutes*(self: View, amountIn: string, amountOut: string, extraParamsJson: string) {.slot.} = proc suggestedRoutes*(self: View, uuid: string, amountIn: string, amountOut: string, extraParamsJson: string) {.slot.} =
var extraParamsTable: Table[string, string] var extraParamsTable: Table[string, string]
try: try:
if extraParamsJson.len > 0: if extraParamsJson.len > 0:
@ -201,11 +204,12 @@ QtObject:
error "Error parsing extraParamsJson: ", msg=e.msg error "Error parsing extraParamsJson: ", msg=e.msg
self.delegate.suggestedRoutes( self.delegate.suggestedRoutes(
$genUUID(), uuid,
self.sendType, self.sendType,
self.selectedSenderAccountAddress, self.selectedSenderAccountAddress,
self.selectedRecipient, self.selectedRecipient,
self.selectedAssetKey, self.selectedAssetKey,
self.selectedTokenIsOwnerToken,
amountIn, amountIn,
self.selectedToAssetKey, self.selectedToAssetKey,
amountOut, amountOut,
@ -283,6 +287,7 @@ QtObject:
accountFrom, accountFrom,
accountTo, accountTo,
token, token,
self.selectedTokenIsOwnerToken,
amountIn, amountIn,
toToken, toToken,
amountOut, amountOut,
@ -290,22 +295,9 @@ QtObject:
parseChainIds(disabledToChainIDs), parseChainIds(disabledToChainIDs),
lockedInAmountsTable) lockedInAmountsTable)
proc authenticateAndTransferWithParameters*(self: View, uuid: string, accountFrom: string, accountTo: string, token: string, toToken: string, proc transactionSendingComplete*(self: View, txHash: string, status: string) {.signal.}
sendTypeInt: int, tokenName: string, tokenIsOwnerToken: bool, rawPaths: string, slippagePercentageString: string) {.slot.} = proc sendtransactionSendingCompleteSignal*(self: View, txHash: string, status: string) =
self.transactionSendingComplete(txHash, status)
let sendType = SendType(sendTypeInt)
var slippagePercentage: Option[float]
if sendType == SendType.Swap:
if slippagePercentageString.len > 0:
slippagePercentage = slippagePercentageString.parseFloat().some
self.delegate.authenticateAndTransferWithPaths(accountFrom, accountTo, token,
toToken, uuid, sendType, tokenName, tokenIsOwnerToken, rawPaths, slippagePercentage)
proc transactionSendingComplete*(self: View, txHash: string, success: bool) {.signal.}
proc sendtransactionSendingCompleteSignal*(self: View, txHash: string, success: bool) =
self.transactionSendingComplete(txHash, success)
proc setSenderAccount*(self: View, address: string) {.slot.} = proc setSenderAccount*(self: View, address: string) {.slot.} =
self.setSelectedSenderAccountAddress(address) self.setSelectedSenderAccountAddress(address)

View File

@ -119,7 +119,10 @@ QtObject:
debug "signMessageWithCallback: signing on keycard started successfully" debug "signMessageWithCallback: signing on keycard started successfully"
return return
let finalPassword = self.preparePassword(password) let finalPassword = self.preparePassword(password)
res = self.service.signMessage(address, finalPassword, message) var err: string
(res, err) = self.service.signMessage(address, finalPassword, message)
if err.len > 0:
raise newException(CatchableError, "signMessage failed: " & err)
except Exception as e: except Exception as e:
error "signMessageWithCallback failed: ", msg=e.msg error "signMessageWithCallback failed: ", msg=e.msg
callback(topic, id, "", address, res) callback(topic, id, "", address, res)

View File

@ -7,6 +7,9 @@ const
STT_CONTRACT_ADDRESS_GOERLI* = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a" STT_CONTRACT_ADDRESS_GOERLI* = "0x3d6afaa395c31fcd391fe3d562e75fe9e8ec7e6a"
STT_CONTRACT_ADDRESS_SEPOLIA* = "0xE452027cdEF746c7Cd3DB31CB700428b16cD8E51" STT_CONTRACT_ADDRESS_SEPOLIA* = "0xE452027cdEF746c7Cd3DB31CB700428b16cD8E51"
SIGNATURE_LEN* = 130
SIGNATURE_LEN_0X_INCLUDED* = SIGNATURE_LEN + 2
TX_HASH_LEN* = 32 * 2 TX_HASH_LEN* = 32 * 2
TX_HASH_LEN_WITH_PREFIX* = TX_HASH_LEN + 2 TX_HASH_LEN_WITH_PREFIX* = TX_HASH_LEN + 2

View File

@ -4,7 +4,6 @@
import stint import stint
import ../../../backend/backend as backend import ../../../backend/backend as backend
import ../../common/conversion as service_conversion
type type
GetSuggestedRoutesTaskArg* = ref object of QObjectTaskArg GetSuggestedRoutesTaskArg* = ref object of QObjectTaskArg

View File

@ -0,0 +1,142 @@
import json, stint
include ../../common/json_utils
const
TxStatusPending* = "Pending"
TxStatusSuccess* = "Success"
TxStatusFailed* = "Failed"
type
TransactionStatusChange* = ref object
status*: string
hash*: string
chainId*: int
type
ErrorResponse* = ref object
details*: string
code*: string
type
SendDetailsDto* = ref object
uuid*: string
sendType*: int
fromAddress*: string
toAddress*: string
fromToken*: string
toToken*: string
fromAmount*: UInt256 # total amount
toAmount*: UInt256
ownerTokenBeingSent*: bool
errorResponse*: ErrorResponse
username*: string
publicKey*: string
packId*: string
type
SigningDetails* = ref object
address*: string
addressPath*: string
keyUid*: string
signOnKeycard*: bool
hashes*: seq[string]
type
RouterTransactionsForSigningDto* = ref object
sendDetails*: SendDetailsDto
signingDetails*: SigningDetails
type
RouterSentTransaction* = ref object
fromAddress*: string
toAddress*: string
fromChain*: int
toChain*: int
fromToken*: string
toToken*: string
amount*: UInt256 # amount of the transaction
hash*: string
approvalTx*: bool
type
RouterSentTransactionsDto* = ref object
sendDetails*: SendDetailsDto
sentTransactions*: seq[RouterSentTransaction]
proc toTransactionStatusChange*(jsonObj: JsonNode): TransactionStatusChange =
result = TransactionStatusChange()
discard jsonObj.getProp("status", result.status)
discard jsonObj.getProp("hash", result.hash)
discard jsonObj.getProp("chainId", result.chainId)
proc toErrorResponse*(jsonObj: JsonNode): ErrorResponse =
result = ErrorResponse()
if jsonObj.contains("details"):
result.details = jsonObj["details"].getStr
if jsonObj.contains("code"):
result.code = jsonObj["code"].getStr
proc toSendDetailsDto*(jsonObj: JsonNode): SendDetailsDto =
result = SendDetailsDto()
discard jsonObj.getProp("uuid", result.uuid)
discard jsonObj.getProp("sendType", result.sendType)
discard jsonObj.getProp("fromAddress", result.fromAddress)
discard jsonObj.getProp("toAddress", result.toAddress)
discard jsonObj.getProp("fromToken", result.fromToken)
discard jsonObj.getProp("toToken", result.toToken)
discard jsonObj.getProp("ownerTokenBeingSent", result.ownerTokenBeingSent)
var tmpObj: JsonNode
if jsonObj.getProp("fromAmount", tmpObj):
result.fromAmount = stint.fromHex(UInt256, tmpObj.getStr)
if jsonObj.getProp("toAmount", tmpObj):
result.toAmount = stint.fromHex(UInt256, tmpObj.getStr)
if jsonObj.getProp("errorResponse", tmpObj) and tmpObj.kind == JObject:
result.errorResponse = toErrorResponse(tmpObj)
discard jsonObj.getProp("username", result.username)
discard jsonObj.getProp("publicKey", result.publicKey)
if jsonObj.getProp("packId", tmpObj):
let packId = stint.fromHex(UInt256, tmpObj.getStr)
result.packId = $packId
proc toSigningDetails*(jsonObj: JsonNode): SigningDetails =
result = SigningDetails()
discard jsonObj.getProp("address", result.address)
discard jsonObj.getProp("addressPath", result.addressPath)
discard jsonObj.getProp("keyUid", result.keyUid)
discard jsonObj.getProp("signOnKeycard", result.signOnKeycard)
var tmpObj: JsonNode
if jsonObj.getProp("hashes", tmpObj) and tmpObj.kind == JArray:
for tx in tmpObj:
result.hashes.add(tx.getStr)
proc toRouterTransactionsForSigningDto*(jsonObj: JsonNode): RouterTransactionsForSigningDto =
result = RouterTransactionsForSigningDto()
var tmpObj: JsonNode
if jsonObj.getProp("sendDetails", tmpObj) and tmpObj.kind == JObject:
result.sendDetails = toSendDetailsDto(tmpObj)
if jsonObj.getProp("signingDetails", tmpObj) and tmpObj.kind == JObject:
result.signingDetails = toSigningDetails(tmpObj)
proc toRouterSentTransaction*(jsonObj: JsonNode): RouterSentTransaction =
result = RouterSentTransaction()
discard jsonObj.getProp("fromAddress", result.fromAddress)
discard jsonObj.getProp("toAddress", result.toAddress)
discard jsonObj.getProp("fromChain", result.fromChain)
discard jsonObj.getProp("toChain", result.toChain)
discard jsonObj.getProp("fromToken", result.fromToken)
discard jsonObj.getProp("toToken", result.toToken)
discard jsonObj.getProp("hash", result.hash)
discard jsonObj.getProp("approvalTx", result.approvalTx)
var tmpObj: JsonNode
if jsonObj.getProp("amount", tmpObj):
result.amount = stint.fromHex(UInt256, tmpObj.getStr)
proc toRouterSentTransactionsDto*(jsonObj: JsonNode): RouterSentTransactionsDto =
result = RouterSentTransactionsDto()
var tmpObj: JsonNode
if jsonObj.getProp("sendDetails", tmpObj) and tmpObj.kind == JObject:
result.sendDetails = toSendDetailsDto(tmpObj)
if jsonObj.getProp("sentTransactions", tmpObj) and tmpObj.kind == JArray:
for tx in tmpObj:
result.sentTransactions.add(toRouterSentTransaction(tx))

View File

@ -4,8 +4,8 @@ import backend/collectibles as collectibles
import backend/transactions as transactions import backend/transactions as transactions
import backend/backend import backend/backend
import backend/eth import backend/eth
import backend/wallet
import app_service/service/ens/utils as ens_utils
import app_service/common/utils as common_utils import app_service/common/utils as common_utils
import app_service/common/types as common_types import app_service/common/types as common_types
@ -19,15 +19,14 @@ import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/network/service as network_service import app_service/service/network/service as network_service
import app_service/service/token/service as token_service import app_service/service/token/service as token_service
import app_service/service/settings/service as settings_service import app_service/service/settings/service as settings_service
import app_service/service/eth/dto/transaction as transaction_data_dto
import app_service/service/eth/dto/[coder, method_dto]
import ./dto as transaction_dto import ./dto as transaction_dto
import ./dtoV2 import ./dtoV2
import ./dto_conversion import ./dto_conversion
import ./router_transactions_dto
import app_service/service/eth/utils as eth_utils import app_service/service/eth/utils as eth_utils
export transaction_dto export transaction_dto, router_transactions_dto
export transactions.TransactionsSignatures export transactions.TransactionsSignatures
logScope: logScope:
@ -37,6 +36,8 @@ include async_tasks
include app_service/common/json_utils include app_service/common/json_utils
# Signals which may be emitted by this service: # Signals which may be emitted by this service:
const SIGNAL_SIGN_ROUTER_TRANSACTIONS* = "signRouterTransactions"
const SIGNAL_SENDING_TRANSACTIONS_STARTED* = "sendingTransactionsStarted"
const SIGNAL_TRANSACTION_SENT* = "transactionSent" const SIGNAL_TRANSACTION_SENT* = "transactionSent"
const SIGNAL_SUGGESTED_ROUTES_READY* = "suggestedRoutesReady" const SIGNAL_SUGGESTED_ROUTES_READY* = "suggestedRoutesReady"
const SIGNAL_HISTORY_NON_ARCHIVAL_NODE* = "historyNonArchivalNode" const SIGNAL_HISTORY_NON_ARCHIVAL_NODE* = "historyNonArchivalNode"
@ -44,12 +45,7 @@ const SIGNAL_HISTORY_ERROR* = "historyError"
const SIGNAL_TRANSACTION_DECODED* = "transactionDecoded" const SIGNAL_TRANSACTION_DECODED* = "transactionDecoded"
const SIGNAL_OWNER_TOKEN_SENT* = "ownerTokenSent" const SIGNAL_OWNER_TOKEN_SENT* = "ownerTokenSent"
const SIGNAL_TRANSACTION_SENDING_COMPLETE* = "transactionSendingComplete" const SIGNAL_TRANSACTION_SENDING_COMPLETE* = "transactionSendingComplete"
const SIGNAL_TRANSACTION_STATUS_CHANGED* = "transactionStatusChanged"
const SIMPLE_TX_BRIDGE_NAME = "Transfer"
const HOP_TX_BRIDGE_NAME = "Hop"
const ERC721_TRANSFER_NAME = "ERC721Transfer"
const ERC1155_TRANSFER_NAME = "ERC1155Transfer"
const SWAP_PARASWAP_NAME = "Paraswap"
type TokenTransferMetadata* = object type TokenTransferMetadata* = object
tokenName*: string tokenName*: string
@ -119,6 +115,10 @@ type
fromAmount*: string fromAmount*: string
toTokenKey*: string toTokenKey*: string
toAmount*: string toAmount*: string
approvalTx*: bool
username*: string
publicKey*: string
packId*: string
type type
OwnerTokenSentArgs* = ref object of Args OwnerTokenSentArgs* = ref object of Args
@ -140,6 +140,18 @@ type
dataDecoded*: string dataDecoded*: string
txHash*: string txHash*: string
type
RouterTransactionsForSigningArgs* = ref object of Args
data*: RouterTransactionsForSigningDto
type
RouterTransactionsSendingStartedArgs* = ref object of Args
data*: SendDetailsDto
type
TransactionStatusArgs* = ref object of Args
data*: TransactionStatusChange
QtObject: QtObject:
type Service* = ref object of QObject type Service* = ref object of QObject
events: EventEmitter events: EventEmitter
@ -151,6 +163,7 @@ QtObject:
## Forward declarations ## Forward declarations
proc suggestedRoutesReady(self: Service, uuid: string, route: seq[TransactionPathDtoV2], routeRaw: string, errCode: string, errDescription: string) proc suggestedRoutesReady(self: Service, uuid: string, route: seq[TransactionPathDtoV2], routeRaw: string, errCode: string, errDescription: string)
proc sendTransactionsSignal(self: Service, sendDetails: SendDetailsDto, sentTransactions: seq[RouterSentTransaction] = @[])
proc delete*(self: Service) = proc delete*(self: Service) =
self.QObject.delete self.QObject.delete
@ -184,6 +197,28 @@ QtObject:
self.tokenService.updateTokenPrices(data.updatedPrices) self.tokenService.updateTokenPrices(data.updatedPrices)
self.suggestedRoutesReady(data.uuid, data.bestRoute, data.bestRouteRaw, data.errorCode, data.error) self.suggestedRoutesReady(data.uuid, data.bestRoute, data.bestRouteRaw, data.errorCode, data.error)
self.events.on(SignalType.WalletRouterSendingTransactionsStarted.event) do(e:Args):
var data = WalletSignal(e)
self.events.emit(SIGNAL_SENDING_TRANSACTIONS_STARTED, RouterTransactionsSendingStartedArgs(data: data.routerTransactionsSendingDetails))
# TODO: the line below is to aling with the old implementation, remove it
self.sendTransactionsSignal(data.routerTransactionsSendingDetails)
self.events.on(SignalType.WalletRouterSignTransactions.event) do(e:Args):
var data = WalletSignal(e)
if data.routerTransactionsForSigning.sendDetails.errorResponse.isNil and
not data.routerTransactionsForSigning.signingDetails.isNil:
self.events.emit(SIGNAL_SIGN_ROUTER_TRANSACTIONS, RouterTransactionsForSigningArgs(data: data.routerTransactionsForSigning))
return
self.sendTransactionsSignal(data.routerTransactionsForSigning.sendDetails)
self.events.on(SignalType.WalletRouterTransactionsSent.event) do(e:Args):
var data = WalletSignal(e)
self.sendTransactionsSignal(data.routerSentTransactions.sendDetails, data.routerSentTransactions.sentTransactions)
self.events.on(SignalType.WalletTransactionStatusChanged.event) do(e:Args):
var data = WalletSignal(e)
self.events.emit(SIGNAL_TRANSACTION_STATUS_CHANGED, TransactionStatusArgs(data: data.transactionStatusChange))
self.events.on(PendingTransactionTypeDto.WalletTransfer.event) do(e: Args): self.events.on(PendingTransactionTypeDto.WalletTransfer.event) do(e: Args):
try: try:
var receivedData = TransactionMinedArgs(e) var receivedData = TransactionMinedArgs(e)
@ -287,372 +322,55 @@ QtObject:
) )
self.threadpool.start(arg) self.threadpool.start(arg)
proc createApprovalPath*(self: Service, route: TransactionPathDto, from_addr: string, toAddress: Address, gasFees: string): TransactionBridgeDto = proc sendTransactionsSignal(self: Service, sendDetails: SendDetailsDto, sentTransactions: seq[RouterSentTransaction] = @[]) =
var txData = TransactionDataDto()
let approve = Approve(
to: parseAddress(route.approvalContractAddress),
value: route.approvalAmountRequired,
)
let data = ERC20_procS.toTable["approve"].encodeAbi(approve)
txData = ens_utils.buildTokenTransaction(
parseAddress(from_addr),
toAddress,
$route.gasAmount,
gasFees,
route.gasFees.eip1559Enabled,
$route.gasFees.maxPriorityFeePerGas,
$route.gasFees.maxFeePerGasM
)
txData.data = data
var path = TransactionBridgeDto(bridgeName: SIMPLE_TX_BRIDGE_NAME, chainID: route.fromNetwork.chainId)
path.transferTx = txData
return path
proc createPath*(self: Service, route: TransactionPathDto, txData: TransactionDataDto, tokenSymbol: string, to_addr: string): TransactionBridgeDto =
var path = TransactionBridgeDto(bridgeName: route.bridgeName, chainID: route.fromNetwork.chainId)
var hopTx = TransactionDataDto()
var cbridgeTx = TransactionDataDto()
var eRC721TransferTx = TransactionDataDto()
var eRC1155TransferTx = TransactionDataDto()
var swapTx = TransactionDataDto()
if(route.bridgeName == SIMPLE_TX_BRIDGE_NAME):
path.transferTx = txData
elif(route.bridgeName == HOP_TX_BRIDGE_NAME):
hopTx = txData
hopTx.chainID = route.fromNetwork.chainId.some
hopTx.chainIDTo = route.toNetwork.chainId.some
hopTx.symbol = tokenSymbol.some
hopTx.recipient = parseAddress(to_addr).some
hopTx.amount = route.amountIn.some
hopTx.bonderFee = route.txBonderFees.some
path.hopTx = hopTx
elif(route.bridgeName == ERC721_TRANSFER_NAME):
eRC721TransferTx = txData
eRC721TransferTx.chainID = route.toNetwork.chainId.some
eRC721TransferTx.recipient = parseAddress(to_addr).some
eRC721TransferTx.tokenID = stint.u256(tokenSymbol).some
path.eRC721TransferTx = eRC721TransferTx
elif(route.bridgeName == ERC1155_TRANSFER_NAME):
eRC1155TransferTx = txData
eRC1155TransferTx.chainID = route.toNetwork.chainId.some
eRC1155TransferTx.recipient = parseAddress(to_addr).some
eRC1155TransferTx.tokenID = stint.u256(tokenSymbol).some
eRC1155TransferTx.amount = route.amountIn.some
path.eRC1155TransferTx = eRC1155TransferTx
elif(route.bridgeName == SWAP_PARASWAP_NAME):
swapTx = txData
swapTx.chainID = route.fromNetwork.chainId.some
swapTx.chainIDTo = route.toNetwork.chainId.some
swapTx.tokenIdFrom = route.fromToken.symbol.some
swapTx.tokenIdTo = route.toToken.symbol.some
path.swapTx = swapTx
else:
cbridgeTx = txData
cbridgeTx.chainID = route.toNetwork.chainId.some
cbridgeTx.symbol = tokenSymbol.some
cbridgeTx.recipient = parseAddress(to_addr).some
cbridgeTx.amount = route.amountIn.some
path.cbridgeTx = cbridgeTx
return path
proc sendTransactionSentSignal(self: Service, txType: SendType, fromAddr: string, toAddr: string,
fromTokenKey: string, fromAmount: string, toTokenKey: string, toAmount: string, uuid: string,
routes: seq[TransactionPathDto], response: RpcResponse[JsonNode], err: string = "", tokenName = "", isOwnerToken=false) =
# While preparing the tx in the Send modal user cannot see the address, it's revealed once the tx is sent # While preparing the tx in the Send modal user cannot see the address, it's revealed once the tx is sent
# (there are few places where we display the toast from and link to the etherscan where the address can be seen) # (there are few places where we display the toast from and link to the etherscan where the address can be seen)
# that's why we need to mark the addresses as shown here (safer). # that's why we need to mark the addresses as shown here (safer).
self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: @[fromAddr, toAddr])) self.events.emit(MARK_WALLET_ADDRESSES_AS_SHOWN, WalletAddressesArgs(addresses: @[sendDetails.fromAddress, sendDetails.toAddress]))
if err.len > 0: if not sendDetails.errorResponse.isNil and sendDetails.errorResponse.details.len > 0:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(uuid: uuid, error: err, txType: txType, self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(
fromAddress: fromAddr, toAddress: toAddr, fromTokenKey: fromTokenKey, fromAmount: fromAmount, uuid: sendDetails.uuid,
toTokenKey: toTokenKey, toAmount: toAmount)) error: sendDetails.errorResponse.details,
if txType == SendType.Swap: txType: SendType(sendDetails.sendType),
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("swap", $(%*{"subEvent": "tx error"})) fromAddress: sendDetails.fromAddress,
elif response.result{"hashes"} != nil: toAddress: sendDetails.toAddress,
for route in routes: fromTokenKey: sendDetails.fromToken,
for hash in response.result["hashes"][$route.fromNetwork.chainID]: fromAmount: sendDetails.fromAmount.toString(10),
if isOwnerToken: toTokenKey: sendDetails.toToken,
self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr, toAmount: sendDetails.toAmount.toString(10),
uuid: uuid, tokenName: tokenName, status: ContractTransactionStatus.InProgress)) username: sendDetails.username,
else: publicKey: sendDetails.publicKey,
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr, uuid: uuid , packId: sendDetails.packId
error: "", txType: txType, fromAddress: fromAddr, toAddress: toAddr, fromTokenKey: fromTokenKey, fromAmount: fromAmount, toTokenKey: toTokenKey, toAmount: toAmount)) ))
return
let metadata = TokenTransferMetadata(tokenName: tokenName, isOwnerToken: isOwnerToken) for tx in sentTransactions:
self.watchTransaction(hash.getStr, fromAddr, toAddr, $PendingTransactionTypeDto.WalletTransfer, $(%metadata), route.fromNetwork.chainID, if sendDetails.ownerTokenBeingSent:
fromTokenKey, fromAmount, toTokenKey, toAmount, txType) self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(
chainId: tx.fromChain,
if txType == SendType.Swap: txHash: tx.hash,
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("swap", $(%*{"subEvent": "tx success"})) uuid: sendDetails.uuid,
tokenName: tx.fromToken,
proc isCollectiblesTransfer(self: Service, sendType: SendType): bool = status: ContractTransactionStatus.InProgress
return sendType == ERC721Transfer or sendType == ERC1155Transfer ))
proc sendTypeToMultiTxType(sendType: SendType): transactions.MultiTransactionType =
case sendType
of SendType.Swap:
return transactions.MultiTransactionType.MultiTransactionSwap
of SendType.Approve:
return transactions.MultiTransactionType.MultiTransactionApprove
of SendType.Bridge:
return transactions.MultiTransactionType.MultiTransactionBridge
else:
return transactions.MultiTransactionType.MultiTransactionSend
proc transferEth(
self: Service,
from_addr: string,
to_addr: string,
tokenSymbol: string,
toTokenSymbol: string,
uuid: string,
routes: seq[TransactionPathDto],
password: string,
sendType: SendType,
slippagePercentage: Option[float]
) =
try:
var paths: seq[TransactionBridgeDto] = @[]
var totalAmountToSend: UInt256
var totalAmountToReceive: UInt256
let toAddress = parseAddress(to_addr)
for route in routes:
var txData = TransactionDataDto()
var gasFees: string = ""
if( not route.gasFees.eip1559Enabled):
gasFees = $route.gasFees.gasPrice
if route.approvalRequired:
paths.add(self.createApprovalPath(route, from_addr, toAddress, gasFees))
totalAmountToSend += route.amountIn
totalAmountToReceive += route.amountOut
txData = ens_utils.buildTransaction(parseAddress(from_addr), route.amountIn,
$route.gasAmount, gasFees, route.gasFees.eip1559Enabled, $route.gasFees.maxPriorityFeePerGas, $route.gasFees.maxFeePerGasM)
txData.to = parseAddress(to_addr).some
if sendType == SendType.Swap:
txData.slippagePercentage = slippagePercentage
paths.add(self.createPath(route, txData, tokenSymbol, to_addr))
var mtCommand = MultiTransactionCommandDto(
fromAddress: from_addr,
toAddress: to_addr,
fromAsset: tokenSymbol,
toAsset: toTokenSymbol,
fromAmount: "0x" & totalAmountToSend.toHex,
multiTxType: sendTypeToMultiTxType(sendType),
)
if sendType == SendType.Swap:
mtCommand.toAmount = "0x" & totalAmountToReceive.toHex
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("swap", $(%*{"subEvent": "send tx"}))
let response = transactions.createMultiTransaction(
mtCommand,
paths,
password,
)
if password != "":
self.sendTransactionSentSignal(sendType, from_addr, to_addr, tokenSymbol, totalAmountToSend.toString(10),
toTokenSymbol, totalAmountToReceive.toString(10), uuid, routes, response)
except Exception as e:
self.sendTransactionSentSignal(sendType, from_addr, to_addr, tokenSymbol, "",
toTokenSymbol, "", uuid, @[], RpcResponse[JsonNode](), self.extractRpcErrorMessage(e.msg))
proc mustIgnoreApprovalRequests(sendType: SendType): bool =
# Swap requires approvals to be done in advance in a separate Tx
return sendType == SendType.Swap
# in case of collectibles transfer, assetKey is used to get the contract address and token id
# in case of asset transfer, asset is valid and used to get the asset symbol and contract address
proc transferToken(
self: Service,
from_addr: string,
to_addr: string,
assetKey: string,
asset: TokenBySymbolItem,
toAssetKey: string,
toAsset: TokenBySymbolItem,
uuid: string,
routes: seq[TransactionPathDto],
password: string,
sendType: SendType,
tokenName: string,
isOwnerToken: bool,
slippagePercentage: Option[float]
) =
var
toContractAddress: Address
paths: seq[TransactionBridgeDto] = @[]
totalAmountToSend: UInt256
totalAmountToReceive: UInt256
mtCommand = MultiTransactionCommandDto(
fromAddress: from_addr,
toAddress: to_addr,
fromAsset: if not asset.isNil: asset.symbol else: assetKey,
toAsset: if not toAsset.isNil: toAsset.symbol else: toAssetKey,
multiTxType: sendTypeToMultiTxType(sendType),
)
# if collectibles transfer ...
if asset.isNil:
let contract_tokenId = assetKey.split(":")
if contract_tokenId.len == 2:
toContractAddress = parseAddress(contract_tokenId[0])
mtCommand.fromAsset = contract_tokenId[1]
mtCommand.toAsset = contract_tokenId[1]
else: else:
error "Invalid assetKey for collectibles transfer", assetKey=assetKey self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(
return chainId: tx.fromChain,
txHash: tx.hash,
try: uuid: sendDetails.uuid,
for route in routes: txType: SendType(sendDetails.sendType),
var txData = TransactionDataDto() fromAddress: tx.fromAddress,
var gasFees: string = "" toAddress: tx.toAddress,
fromTokenKey: tx.fromToken,
# If not collectible ... fromAmount: tx.amount.toString(10),
if not asset.isNil: toTokenKey: tx.toToken,
var foundAddress = false toAmount: tx.amount.toString(10),
for addressPerChain in asset.addressPerChainId: approvalTx: tx.approvalTx,
if addressPerChain.chainId == route.fromNetwork.chainId: username: sendDetails.username,
toContractAddress = parseAddress(addressPerChain.address) publicKey: sendDetails.publicKey,
foundAddress = true packId: sendDetails.packId
break ))
if not foundAddress:
error "Contract address not found for asset", assetKey=assetKey
return
if not route.gasFees.eip1559Enabled:
gasFees = $route.gasFees.gasPrice
if route.approvalRequired and not mustIgnoreApprovalRequests(sendType):
let approvalPath = self.createApprovalPath(route, mtCommand.fromAddress, toContractAddress, gasFees)
paths.add(approvalPath)
totalAmountToSend += route.amountIn
totalAmountToReceive += route.amountOut
if sendType == SendType.Approve:
# We only do the approvals
continue
let transfer = Transfer(
to: parseAddress(mtCommand.toAddress),
value: route.amountIn,
)
let data = ERC20_procS.toTable["transfer"].encodeAbi(transfer)
txData = ens_utils.buildTokenTransaction(
parseAddress(mtCommand.fromAddress),
toContractAddress,
$route.gasAmount,
gasFees,
route.gasFees.eip1559Enabled,
$route.gasFees.maxPriorityFeePerGas,
$route.gasFees.maxFeePerGasM
)
txData.data = data
if sendType == SendType.Swap:
txData.slippagePercentage = slippagePercentage
let path = self.createPath(route, txData, mtCommand.toAsset, mtCommand.toAddress)
paths.add(path)
mtCommand.fromAmount = "0x" & totalAmountToSend.toHex
if sendType == SendType.Swap:
mtCommand.toAmount = "0x" & totalAmountToReceive.toHex
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("swap", $(%*{"subEvent": "send tx"}))
let response = transactions.createMultiTransaction(mtCommand, paths, password)
if password != "":
self.sendTransactionSentSignal(sendType, mtCommand.fromAddress, mtCommand.toAddress,
assetKey, totalAmountToSend.toString(10), toAssetKey, totalAmountToReceive.toString(10),
uuid, routes, response, err="", tokenName, isOwnerToken)
except Exception as e:
self.sendTransactionSentSignal(sendType, mtCommand.fromAddress, mtCommand.toAddress,
assetKey, "", toAssetKey, "",
uuid, @[], RpcResponse[JsonNode](), self.extractRpcErrorMessage(e.msg))
proc transfer*(
self: Service,
fromAddr: string,
toAddr: string,
assetKey: string,
toAssetKey: string,
uuid: string,
selectedRoutes: seq[TransactionPathDto],
password: string,
sendType: SendType,
usePassword: bool,
doHashing: bool,
tokenName: string,
isOwnerToken: bool,
slippagePercentage: Option[float]
) =
var finalPassword = ""
if usePassword:
finalPassword = password
if doHashing:
finalPassword = common_utils.hashPassword(password)
try:
var chainID = 0
if(selectedRoutes.len > 0):
chainID = selectedRoutes[0].fromNetwork.chainID
# asset == nil means transferToken is executed for a collectibles transfer
var
asset: TokenBySymbolItem
toAsset: TokenBySymbolItem
if not self.isCollectiblesTransfer(sendType):
asset = self.tokenService.getTokenBySymbolByTokensKey(assetKey)
if asset.isNil:
error "Asset not found for", assetKey=assetKey
return
toAsset = asset
if sendType == Swap:
toAsset = self.tokenService.getTokenBySymbolByTokensKey(toAssetKey)
if toAsset.isNil:
error "Asset not found for", assetKey=assetKey
return
let network = self.networkService.getNetworkByChainId(chainID)
if not network.isNil and network.nativeCurrencySymbol == asset.symbol:
self.transferEth(fromAddr, toAddr, asset.symbol, toAsset.symbol, uuid, selectedRoutes, finalPassword, sendType, slippagePercentage)
return
self.transferToken(fromAddr, toAddr, assetKey, asset, toAssetKey, toAsset, uuid, selectedRoutes, finalPassword,
sendType, tokenName, isOwnerToken, slippagePercentage)
except Exception as e:
self.sendTransactionSentSignal(sendType, fromAddr, toAddr, assetKey, "", toAssetKey, "", uuid, @[], RpcResponse[JsonNode](), self.extractRpcErrorMessage(e.msg))
proc proceedWithTransactionsSignatures*(self: Service, fromAddr: string, toAddr: string,
fromTokenKey: string, toTokenKey: string, uuid: string, signatures: TransactionsSignatures,
selectedRoutes: seq[TransactionPathDto], sendType: SendType) =
try:
let response = transactions.proceedWithTransactionsSignatures(signatures)
var totalAmountToSend: UInt256
var totalAmountToReceive: UInt256
for route in selectedRoutes:
totalAmountToSend += route.amountIn
totalAmountToReceive += route.amountOut
self.sendTransactionSentSignal(sendType, fromAddr, toAddr, fromTokenKey, totalAmountToSend.toString(10), toTokenKey, totalAmountToReceive.toString(10), uuid, selectedRoutes, response)
except Exception as e:
self.sendTransactionSentSignal(sendType, fromAddr, toAddr, fromTokenKey, "", toTokenKey, "",
uuid, @[], RpcResponse[JsonNode](), fmt"Error proceeding with transactions signatures: {e.msg}")
proc suggestedFees*(self: Service, chainId: int): SuggestedFeesDto = proc suggestedFees*(self: Service, chainId: int): SuggestedFeesDto =
try: try:
@ -688,6 +406,7 @@ QtObject:
accountFrom: string, accountFrom: string,
accountTo: string, accountTo: string,
token: string, token: string,
tokenIsOwnerToken: bool,
amountIn: string, amountIn: string,
toToken: string = "", toToken: string = "",
amountOut: string = "", amountOut: string = "",
@ -706,7 +425,7 @@ QtObject:
try: try:
let res = eth.suggestedRoutesAsync(uuid, ord(sendType), accountFrom, accountTo, amountInHex, amountOutHex, token, let res = eth.suggestedRoutesAsync(uuid, ord(sendType), accountFrom, accountTo, amountInHex, amountOutHex, token,
toToken, disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable) tokenIsOwnerToken, toToken, disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable)
except CatchableError as e: except CatchableError as e:
error "suggestedRoutes", exception=e.msg error "suggestedRoutes", exception=e.msg
@ -747,3 +466,38 @@ proc getMultiTransactions*(transactionIDs: seq[int]): seq[MultiTransactionDto] =
let errDescription = e.msg let errDescription = e.msg
error "error: ", errDescription error "error: ", errDescription
return return
proc signMessage*(self: Service, address: string, hashedPassword: string, hashedMessage: string): tuple[res: string, err: string] =
var signMsgRes: JsonNode
let err = wallet.signMessage(signMsgRes,
hashedMessage,
address,
hashedPassword)
if err.len > 0:
error "status-go - wallet_signMessage failed", err=err
result.err = err
return
result.res = signMsgRes.getStr
return
proc buildTransactionsFromRoute*(self: Service, uuid: string, slippagePercentage: float): string =
var response: JsonNode
let err = transactions.buildTransactionsFromRoute(response, uuid, slippagePercentage)
if err.len > 0:
error "status-go - transfer failed", err=err
return err
if response.kind != JNull:
error "unexpected transfer response"
return "unexpected transfer response"
return ""
proc sendRouterTransactionsWithSignatures*(self: Service, uuid: string, signatures: TransactionsSignatures): string =
var response: JsonNode
let err = transactions.sendRouterTransactionsWithSignatures(response, uuid, signatures)
if err.len > 0:
error "status-go - wallet_sendRouterTransactionsWithSignatures failed", err=err
return err
if response.kind != JNull:
error "unexpected sending transactions response"
return "unexpected sending transactions response"
return ""

View File

@ -138,15 +138,8 @@ QtObject:
return "" return ""
return hashRes.result.getStr() return hashRes.result.getStr()
proc signMessage*(self: Service, address: string, hashedPassword: string, hashedMessage: string): string = proc signMessage*(self: Service, address: string, hashedPassword: string, hashedMessage: string): tuple[res: string, err: string] =
var signMsgRes: JsonNode return self.transactions.signMessage(address, hashedPassword, hashedMessage)
let err = wallet.signMessage(signMsgRes,
hashedMessage,
address,
hashedPassword)
if err.len > 0:
error "status-go - wallet_signMessage failed", err=err
return signMsgRes.getStr
proc buildTransaction*(self: Service, chainId: int, txJson: string): tuple[txToSign: string, txData: JsonNode] = proc buildTransaction*(self: Service, chainId: int, txJson: string): tuple[txToSign: string, txData: JsonNode] =
var buildTxResponse: JsonNode var buildTxResponse: JsonNode

16
src/backend/common.nim Normal file
View File

@ -0,0 +1,16 @@
import json
import response_type
const NO_RESULT* = "no result"
proc isErrorResponse(rpcResponse: RpcResponse[JsonNode]): bool =
if not rpcResponse.error.isNil:
return true
return false
proc prepareResponse(resultOut: var JsonNode, rpcResponse: RpcResponse[JsonNode]): string =
if isErrorResponse(rpcResponse):
return rpcResponse.error.message
if rpcResponse.result.isNil:
return NO_RESULT
resultOut = rpcResponse.result

View File

@ -39,7 +39,7 @@ proc suggestedFees*(chainId: int): RpcResponse[JsonNode] =
return core.callPrivateRPC("wallet_getSuggestedFees", payload) return core.callPrivateRPC("wallet_getSuggestedFees", payload)
proc prepareDataForSuggestedRoutes(uuid: string, sendType: int, accountFrom: string, accountTo: string, amountIn: string, amountOut: string, proc prepareDataForSuggestedRoutes(uuid: string, sendType: int, accountFrom: string, accountTo: string, amountIn: string, amountOut: string,
token: string, toToken: string, disabledFromChainIDs, disabledToChainIDs: seq[int], lockedInAmounts: Table[string, string], token: string, tokenIsOwnerToken: bool, toToken: string, disabledFromChainIDs, disabledToChainIDs: seq[int], lockedInAmounts: Table[string, string],
extraParamsTable: Table[string, string]): JsonNode = extraParamsTable: Table[string, string]): JsonNode =
let data = %* { let data = %* {
@ -50,6 +50,7 @@ proc prepareDataForSuggestedRoutes(uuid: string, sendType: int, accountFrom: str
"amountIn": amountIn, "amountIn": amountIn,
"amountOut": amountOut, "amountOut": amountOut,
"tokenID": token, "tokenID": token,
"tokenIDIsOwnerToken": tokenIsOwnerToken,
"toTokenID": toToken, "toTokenID": toToken,
"disabledFromChainIDs": disabledFromChainIDs, "disabledFromChainIDs": disabledFromChainIDs,
"disabledToChainIDs": disabledToChainIDs, "disabledToChainIDs": disabledToChainIDs,
@ -69,19 +70,19 @@ proc prepareDataForSuggestedRoutes(uuid: string, sendType: int, accountFrom: str
return %* [data] return %* [data]
proc suggestedRoutes*(sendType: int, accountFrom: string, accountTo: string, amountIn: string, amountOut: string, token: string, proc suggestedRoutes*(sendType: int, accountFrom: string, accountTo: string, amountIn: string, amountOut: string, token: string,
toToken: string, disabledFromChainIDs, disabledToChainIDs: seq[int], lockedInAmounts: Table[string, string], tokenIsOwnerToken: bool, toToken: string, disabledFromChainIDs, disabledToChainIDs: seq[int], lockedInAmounts: Table[string, string],
extraParamsTable: Table[string, string]): RpcResponse[JsonNode] {.raises: [RpcException].} = extraParamsTable: Table[string, string]): RpcResponse[JsonNode] {.raises: [RpcException].} =
let payload = prepareDataForSuggestedRoutes(uuid = "", sendType, accountFrom, accountTo, amountIn, amountOut, token, toToken, disabledFromChainIDs, let payload = prepareDataForSuggestedRoutes(uuid = "", sendType, accountFrom, accountTo, amountIn, amountOut, token, tokenIsOwnerToken, toToken,
disabledToChainIDs, lockedInAmounts, extraParamsTable) disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable)
if payload.isNil: if payload.isNil:
raise newException(RpcException, "Invalid key in extraParamsTable") raise newException(RpcException, "Invalid key in extraParamsTable")
return core.callPrivateRPC("wallet_getSuggestedRoutes", payload) return core.callPrivateRPC("wallet_getSuggestedRoutes", payload)
proc suggestedRoutesAsync*(uuid: string, sendType: int, accountFrom: string, accountTo: string, amountIn: string, amountOut: string, token: string, proc suggestedRoutesAsync*(uuid: string, sendType: int, accountFrom: string, accountTo: string, amountIn: string, amountOut: string, token: string,
toToken: string, disabledFromChainIDs, disabledToChainIDs: seq[int], lockedInAmounts: Table[string, string], tokenIsOwnerToken: bool, toToken: string, disabledFromChainIDs, disabledToChainIDs: seq[int], lockedInAmounts: Table[string, string],
extraParamsTable: Table[string, string]): RpcResponse[JsonNode] {.raises: [RpcException].} = extraParamsTable: Table[string, string]): RpcResponse[JsonNode] {.raises: [RpcException].} =
let payload = prepareDataForSuggestedRoutes(uuid, sendType, accountFrom, accountTo, amountIn, amountOut, token, toToken, disabledFromChainIDs, let payload = prepareDataForSuggestedRoutes(uuid, sendType, accountFrom, accountTo, amountIn, amountOut, token, tokenIsOwnerToken, toToken,
disabledToChainIDs, lockedInAmounts, extraParamsTable) disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable)
if payload.isNil: if payload.isNil:
raise newException(RpcException, "Invalid key in extraParamsTable") raise newException(RpcException, "Invalid key in extraParamsTable")
return core.callPrivateRPC("wallet_getSuggestedRoutesAsync", payload) return core.callPrivateRPC("wallet_getSuggestedRoutesAsync", payload)

View File

@ -1,8 +1,9 @@
import Tables, json, stint, json_serialization, stew/shims/strformat import Tables, json, stint, json_serialization, stew/shims/strformat, logging
import ../app_service/service/eth/dto/transaction
import ./core as core import ./core as core
include common
type type
TransactionsSignatures* = Table[string, tuple[r: string, s: string, v: string]] TransactionsSignatures* = Table[string, tuple[r: string, s: string, v: string]]
@ -82,18 +83,6 @@ proc getTransfersByAddress*(chainId: int, address: string, toBlock: Uint256, lim
proc getTransactionReceipt*(chainId: int, transactionHash: string): RpcResponse[JsonNode] = proc getTransactionReceipt*(chainId: int, transactionHash: string): RpcResponse[JsonNode] =
core.callPrivateRPCWithChainId("eth_getTransactionReceipt", chainId, %* [transactionHash]) core.callPrivateRPCWithChainId("eth_getTransactionReceipt", chainId, %* [transactionHash])
proc createMultiTransaction*(multiTransactionCommand: MultiTransactionCommandDto, data: seq[TransactionBridgeDto], password: string): RpcResponse[JsonNode] =
let payload = %* [multiTransactionCommand, data, password]
result = core.callPrivateRPC("wallet_createMultiTransaction", payload)
proc proceedWithTransactionsSignatures*(signatures: TransactionsSignatures): RpcResponse[JsonNode] =
var data = %* {}
for key, value in signatures:
data[key] = %* { "r": value.r, "s": value.s, "v": value.v }
var payload = %* [data]
result = core.callPrivateRPC("wallet_proceedWithTransactionsSignatures", payload)
proc getMultiTransactions*(transactionIDs: seq[int]): RpcResponse[JsonNode] = proc getMultiTransactions*(transactionIDs: seq[int]): RpcResponse[JsonNode] =
let payload = %* [transactionIDs] let payload = %* [transactionIDs]
result = core.callPrivateRPC("wallet_getMultiTransactions", payload) result = core.callPrivateRPC("wallet_getMultiTransactions", payload)
@ -101,3 +90,31 @@ proc getMultiTransactions*(transactionIDs: seq[int]): RpcResponse[JsonNode] =
proc watchTransaction*(chainId: int, hash: string): RpcResponse[JsonNode] = proc watchTransaction*(chainId: int, hash: string): RpcResponse[JsonNode] =
let payload = %* [chainId, hash] let payload = %* [chainId, hash]
core.callPrivateRPC("wallet_watchTransactionByChainID", payload) core.callPrivateRPC("wallet_watchTransactionByChainID", payload)
proc buildTransactionsFromRoute*(resultOut: var JsonNode, uuid: string, slippagePercentage: float): string =
try:
let payload = %* [{
"uuid": uuid,
"slippagePercentage": slippagePercentage
}]
let response = core.callPrivateRPC("wallet_buildTransactionsFromRoute", payload)
return prepareResponse(resultOut, response)
except Exception as e:
warn e.msg
return e.msg
proc sendRouterTransactionsWithSignatures*(resultOut: var JsonNode, uuid: string, signatures: TransactionsSignatures): string =
try:
var jsonSignatures = %* {}
for key, value in signatures:
jsonSignatures[key] = %* { "r": value.r, "s": value.s, "v": value.v }
var payload = %* [{
"uuid": uuid,
"signatures": jsonSignatures
}]
let response = core.callPrivateRPC("wallet_sendRouterTransactionsWithSignatures", payload)
return prepareResponse(resultOut, response)
except Exception as e:
warn e.msg
return e.msg

View File

@ -4,6 +4,8 @@ from ./gen import rpc
import status_go import status_go
include common
rpc(signMessage, "wallet"): rpc(signMessage, "wallet"):
message: string message: string
address: string address: string
@ -24,17 +26,6 @@ rpc(sendTransactionWithSignature, "wallet"):
sendTxArgsJson: string sendTxArgsJson: string
signature: string signature: string
proc isErrorResponse(rpcResponse: RpcResponse[JsonNode]): bool =
if not rpcResponse.error.isNil:
return true
return false
proc prepareResponse(resultOut: var JsonNode, rpcResponse: RpcResponse[JsonNode]): string =
if isErrorResponse(rpcResponse):
return rpcResponse.error.message
if rpcResponse.result.isNil:
return "no result"
resultOut = rpcResponse.result
## Signs the provided message with the provided account using the provided hashed password, performs `crypto.Sign` ## Signs the provided message with the provided account using the provided hashed password, performs `crypto.Sign`
## `resultOut` represents a json object that contains the signature if the call was successful, or `nil` ## `resultOut` represents a json object that contains the signature if the call was successful, or `nil`

View File

@ -71,7 +71,7 @@ SplitView {
readonly property bool areTestNetworksEnabled: true readonly property bool areTestNetworksEnabled: true
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription) signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId, var txHash, var uuid, var error) signal transactionSent(var chainId, var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success) signal transactionSendingComplete(var txHash, var status)
} }
walletAssetsStore: WalletAssetsStore { walletAssetsStore: WalletAssetsStore {
id: thisWalletAssetStore id: thisWalletAssetStore

View File

@ -75,7 +75,7 @@ SplitView {
id: dSwapStore id: dSwapStore
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription) signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId, var txHash, var uuid, var error) signal transactionSent(var chainId, var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success) signal transactionSendingComplete(var txHash, var status)
readonly property var accounts: WalletAccountsModel {} readonly property var accounts: WalletAccountsModel {}
readonly property var flatNetworks: NetworksModel.flatNetworks readonly property var flatNetworks: NetworksModel.flatNetworks
@ -312,7 +312,7 @@ SplitView {
dSwapStore.transactionSent(networksComboBox.currentValue, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", d.uuid, "") dSwapStore.transactionSent(networksComboBox.currentValue, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", d.uuid, "")
})() })()
Backpressure.debounce(this, 2000, () => { Backpressure.debounce(this, 2000, () => {
dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", true) dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Success")
})() })()
fetchSuggestedRoutesSpy.wait() fetchSuggestedRoutesSpy.wait()
Backpressure.debounce(this, 1000, () => { Backpressure.debounce(this, 1000, () => {
@ -352,7 +352,7 @@ SplitView {
dSwapStore.transactionSent(networksComboBox.currentValue, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", d.uuid, "") dSwapStore.transactionSent(networksComboBox.currentValue, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", d.uuid, "")
})() })()
Backpressure.debounce(this, 2000, () => { Backpressure.debounce(this, 2000, () => {
dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", false) dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Failed")
})() })()
} }
} }
@ -433,7 +433,7 @@ SplitView {
Button { Button {
text: "emit approval completed successfully" text: "emit approval completed successfully"
onClicked: { onClicked: {
dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", true) dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Success")
} }
visible: advancedSignalsCheckBox.checked visible: advancedSignalsCheckBox.checked
} }
@ -441,7 +441,7 @@ SplitView {
Button { Button {
text: "emit approval completed with failure" text: "emit approval completed with failure"
onClicked: { onClicked: {
dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", false) dSwapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Failed")
} }
visible: advancedSignalsCheckBox.checked visible: advancedSignalsCheckBox.checked
} }

View File

@ -29,7 +29,7 @@ Item {
readonly property var swapStore: SwapStore { readonly property var swapStore: SwapStore {
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription) signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId,var txHash, var uuid, var error) signal transactionSent(var chainId,var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success) signal transactionSendingComplete(var txHash, var status)
readonly property var accounts: WalletAccountsModel {} readonly property var accounts: WalletAccountsModel {}
readonly property var flatNetworks: NetworksModel.flatNetworks readonly property var flatNetworks: NetworksModel.flatNetworks
@ -1548,7 +1548,7 @@ Item {
root.swapAdaptor.currencyStore.currentCurrency)) root.swapAdaptor.currencyStore.currentCurrency))
// simulate user click on approve button and approval failed // simulate user click on approve button and approval failed
root.swapStore.transactionSent(root.swapFormData.selectedNetworkChainId, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", root.swapAdaptor.uuid, "") root.swapStore.transactionSent(root.swapAdaptor.uuid, root.swapFormData.selectedNetworkChainId, true, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "")
verify(root.swapAdaptor.approvalPending) verify(root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful) verify(!root.swapAdaptor.approvalSuccessful)
@ -1562,7 +1562,7 @@ Item {
root.swapAdaptor.currencyStore.currentCurrency)) root.swapAdaptor.currencyStore.currentCurrency))
// simulate approval tx was unsuccessful // simulate approval tx was unsuccessful
root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", false) root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Failed")
verify(!root.swapAdaptor.approvalPending) verify(!root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful) verify(!root.swapAdaptor.approvalSuccessful)
@ -1577,7 +1577,7 @@ Item {
// simulate user click on approve button and successful approval tx made // simulate user click on approve button and successful approval tx made
signButton.clicked() signButton.clicked()
root.swapStore.transactionSent(root.swapFormData.selectedNetworkChainId, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", root.swapAdaptor.uuid, "") root.swapStore.transactionSent(root.swapAdaptor.uuid, root.swapFormData.selectedNetworkChainId, true, "0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "")
verify(root.swapAdaptor.approvalPending) verify(root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful) verify(!root.swapAdaptor.approvalSuccessful)
@ -1590,30 +1590,29 @@ Item {
root.swapAdaptor.swapOutputData.totalFees, root.swapAdaptor.swapOutputData.totalFees,
root.swapAdaptor.currencyStore.currentCurrency)) root.swapAdaptor.currencyStore.currentCurrency))
root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Success")
// simulate approval tx was successful // simulate approval tx was successful
signButton.clicked() signButton.clicked()
root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", true)
// check if fetchSuggestedRoutes called root.swapStore.transactionSendingComplete("0x877ffe47fc29340312611d4e833ab189fe4f4152b01cc9a05bb4125b81b2a89a", "Success")
fetchSuggestedRoutesCalled.wait()
// verify loading state was set and no errors currently
verifyLoadingAndNoErrorsState(payPanel, receivePanel)
verify(!root.swapAdaptor.approvalPending) verify(!root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful) verify(root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible) verify(!errorTag.visible)
verify(!signButton.interactive) verify(signButton.interactive)
verify(!signButton.loadingWithText) verify(!signButton.loadingWithText)
compare(signButton.text, qsTr("Swap")) compare(signButton.text, qsTr("Swap"))
compare(maxFeesValue.text, Constants.dummyText) compare(maxFeesValue.text, root.swapAdaptor.currencyStore.formatCurrencyAmount(
root.swapAdaptor.swapOutputData.totalFees,
root.swapAdaptor.currencyStore.currentCurrency))
let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval
txHasRouteNoApproval.uuid = root.swapAdaptor.uuid txHasRouteNoApproval.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "") root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "")
verify(!root.swapAdaptor.approvalPending) verify(!root.swapAdaptor.approvalPending)
verify(!root.swapAdaptor.approvalSuccessful) verify(root.swapAdaptor.approvalSuccessful)
verify(!errorTag.visible) verify(!errorTag.visible)
verify(signButton.enabled) verify(signButton.enabled)
verify(!signButton.loadingWithText) verify(!signButton.loadingWithText)
@ -1784,9 +1783,6 @@ Item {
let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval let txHasRouteNoApproval = root.dummySwapTransactionRoutes.txHasRouteNoApproval
txHasRouteNoApproval.uuid = root.swapAdaptor.uuid txHasRouteNoApproval.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "") root.swapStore.suggestedRoutesReady(txHasRouteNoApproval, "", "")
// check if fetch occurs automatically after 15 seconds
fetchSuggestedRoutesCalled.wait()
} }
function test_deleteing_input_characters_data() { function test_deleteing_input_characters_data() {
@ -1833,38 +1829,38 @@ Item {
root.swapFormData.autoRefreshTime = 1200 root.swapFormData.autoRefreshTime = 1200
// Launch popup // Launch popup
launchAndVerfyModal() // launchAndVerfyModal()
// check if fetchSuggestedRoutes called // // check if fetchSuggestedRoutes called
tryCompare(fetchSuggestedRoutesCalled, "count", 1) // tryCompare(fetchSuggestedRoutesCalled, "count", 1)
// no new calls to fetch new proposal should be made as the proposal is still loading // no new calls to fetch new proposal should be made as the proposal is still loading
wait(root.swapFormData.autoRefreshTime*2) // wait(root.swapFormData.autoRefreshTime*2)
compare(fetchSuggestedRoutesCalled.count, 1) // compare(fetchSuggestedRoutesCalled.count, 1)
// emit routes ready // // emit routes ready
let txHasRouteApproval = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded // let txHasRouteApproval = root.dummySwapTransactionRoutes.txHasRoutesApprovalNeeded
txHasRouteApproval.uuid = root.swapAdaptor.uuid // txHasRouteApproval.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txHasRouteApproval, "", "") // root.swapStore.suggestedRoutesReady(txHasRouteApproval, "", "")
// now refresh can occur as no propsal or signing is pending // // now refresh can occur as no propsal or signing is pending
tryCompare(fetchSuggestedRoutesCalled, "count", 2) // tryCompare(fetchSuggestedRoutesCalled, "count", 2)
// emit routes ready // // emit routes ready
txHasRouteApproval.uuid = root.swapAdaptor.uuid // txHasRouteApproval.uuid = root.swapAdaptor.uuid
root.swapStore.suggestedRoutesReady(txHasRouteApproval, "", "") // root.swapStore.suggestedRoutesReady(txHasRouteApproval, "", "")
verify(root.swapAdaptor.swapOutputData.approvalNeeded) // verify(root.swapAdaptor.swapOutputData.approvalNeeded)
verify(!root.swapAdaptor.approvalPending) // verify(!root.swapAdaptor.approvalPending)
// sign approval and check that auto refresh doesnt occur // // sign approval and check that auto refresh doesnt occur
root.swapAdaptor.sendApproveTx() // root.swapAdaptor.sendApproveTx()
// no new calls to fetch new proposal should be made as the approval is pending // // no new calls to fetch new proposal should be made as the approval is pending
verify(root.swapAdaptor.swapOutputData.approvalNeeded) // verify(root.swapAdaptor.swapOutputData.approvalNeeded)
verify(root.swapAdaptor.approvalPending) // verify(root.swapAdaptor.approvalPending)
wait(root.swapFormData.autoRefreshTime*2) // wait(root.swapFormData.autoRefreshTime*2)
compare(fetchSuggestedRoutesCalled.count, 2) // compare(fetchSuggestedRoutesCalled.count, 2)
} }
} }
} }

View File

@ -39,17 +39,6 @@ StatusDialog {
root.swapAdaptor.fetchSuggestedRoutes(payPanel.rawValue) root.swapAdaptor.fetchSuggestedRoutes(payPanel.rawValue)
}) })
property Timer autoRefreshTimer: Timer {
interval: root.swapInputParamsForm.autoRefreshTime
running: false
repeat: false
onTriggered: {
if(!root.swapAdaptor.swapProposalLoading && !root.swapAdaptor.approvalPending) {
d.fetchSuggestedRoutes()
}
}
}
function fetchSuggestedRoutes() { function fetchSuggestedRoutes() {
if (root.swapInputParamsForm.isFormFilledCorrectly()) { if (root.swapInputParamsForm.isFormFilledCorrectly()) {
root.swapAdaptor.swapProposalLoading = true root.swapAdaptor.swapProposalLoading = true
@ -91,19 +80,6 @@ StatusDialog {
} }
} }
Connections {
target: root.swapAdaptor
function onApprovalSuccessfulChanged() {
// perform a recalculation to make sure expected outcome shown is accurate
if(root.swapAdaptor.approvalSuccessful) {
d.fetchSuggestedRoutes()
}
}
function onSuggestedRoutesReady() {
d.autoRefreshTimer.restart()
}
}
// needed as the first time the value not loaded correctly without this Binding // needed as the first time the value not loaded correctly without this Binding
Binding { Binding {
target: root.swapAdaptor target: root.swapAdaptor

View File

@ -264,7 +264,7 @@ QObject {
root.suggestedRoutesReady() root.suggestedRoutesReady()
} }
function onTransactionSent(chainId, txHash, uuid, error) { function onTransactionSent(uuid, chainId, approvalTx, txHash, error) {
if(root.swapOutputData.approvalNeeded) { if(root.swapOutputData.approvalNeeded) {
if (uuid !== d.uuid || !!error) { if (uuid !== d.uuid || !!error) {
root.approvalPending = false root.approvalPending = false
@ -276,11 +276,15 @@ QObject {
} }
} }
function onTransactionSendingComplete(txHash, success) { function onTransactionSendingComplete(txHash, status) {
if(d.txHash === txHash && root.swapOutputData.approvalNeeded && root.approvalPending) { if(d.txHash === txHash && root.swapOutputData.approvalNeeded && root.approvalPending) {
root.approvalPending = false root.approvalPending = false
root.approvalSuccessful = success root.approvalSuccessful = status == "Success" // TODO: make a all tx statuses Constants (success, pending, failed)
d.txHash = "" d.txHash = ""
if (root.approvalSuccessful) {
root.swapOutputData.approvalNeeded = false
}
} }
} }
} }
@ -342,16 +346,12 @@ QObject {
root.approvalPending = true root.approvalPending = true
const accountAddress = root.swapFormData.selectedAccountAddress const accountAddress = root.swapFormData.selectedAccountAddress
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress, root.swapStore.authenticateAndTransfer(d.uuid, "")
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
Constants.SendType.Approve, "", false, root.swapOutputData.rawPaths, "")
} }
function sendSwapTx() { function sendSwapTx() {
const accountAddress = root.swapFormData.selectedAccountAddress const accountAddress = root.swapFormData.selectedAccountAddress
root.swapStore.authenticateAndTransfer(d.uuid, accountAddress, accountAddress, root.swapStore.authenticateAndTransfer(d.uuid, root.swapFormData.selectedSlippage)
root.swapFormData.fromTokensKey, root.swapFormData.toTokenKey,
Constants.SendType.Swap, "", false, root.swapOutputData.rawPaths, root.swapFormData.selectedSlippage)
} }
} }

View File

@ -17,7 +17,7 @@ QtObject {
readonly property var walletSectionSendInst: walletSectionSend readonly property var walletSectionSendInst: walletSectionSend
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription) signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId, var txHash, var uuid, var error) signal transactionSent(var uuid, var chainId, var approvalTx, var txHash, var error)
signal transactionSendingComplete(var txHash, var success) signal transactionSendingComplete(var txHash, var success)
readonly property Connections walletSectionSendConnections: Connections { readonly property Connections walletSectionSendConnections: Connections {
@ -25,8 +25,8 @@ QtObject {
function onSuggestedRoutesReady(txRoutes, errCode, errDescription) { function onSuggestedRoutesReady(txRoutes, errCode, errDescription) {
root.suggestedRoutesReady(txRoutes, errCode, errDescription) root.suggestedRoutesReady(txRoutes, errCode, errDescription)
} }
function onTransactionSent(chainId, txHash, uuid, error) { function onTransactionSent(uuid, chainId, approvalTx, txHash, error) {
root.transactionSent(chainId, txHash, uuid, error) root.transactionSent(uuid, chainId, approvalTx, txHash, error)
} }
function onTransactionSendingComplete(txHash, success) { function onTransactionSendingComplete(txHash, success) {
root.transactionSendingComplete(txHash, success) root.transactionSendingComplete(txHash, success)
@ -45,10 +45,8 @@ QtObject {
root.walletSectionSendInst.stopUpdatesForSuggestedRoute() root.walletSectionSendInst.stopUpdatesForSuggestedRoute()
} }
function authenticateAndTransfer(uuid, accountFrom, accountTo, function authenticateAndTransfer(uuid, slippagePercentage) {
tokenFrom, tokenTo, sendType, tokenName, tokenIsOwnerToken, paths, slippagePercentage) { root.walletSectionSendInst.authenticateAndTransfer(uuid, slippagePercentage)
root.walletSectionSendInst.authenticateAndTransferWithParameters(uuid, accountFrom, accountTo,
tokenFrom, tokenTo, sendType, tokenName, tokenIsOwnerToken, paths, slippagePercentage)
} }
function getWei2Eth(wei, decimals) { function getWei2Eth(wei, decimals) {

View File

@ -78,7 +78,7 @@ StatusDialog {
popup.isLoading = true popup.isLoading = true
d.routerError = "" d.routerError = ""
d.routerErrorDetails = "" d.routerErrorDetails = ""
popup.store.suggestedRoutes(d.isCollectiblesTransfer ? "1" : amountToSend.amount, "0", d.extraParamsJson) popup.store.suggestedRoutes(d.uuid, d.isCollectiblesTransfer ? "1" : amountToSend.amount, "0", d.extraParamsJson)
} }
}) })
@ -788,7 +788,7 @@ StatusDialog {
popup.isLoading = false popup.isLoading = false
} }
function onTransactionSent(chainId: int, txHash: string, uuid: string, error: string) { function onTransactionSent(uuid: string, chainId: int, approvalTx: bool, txHash: string, error: string) {
d.isPendingTx = false d.isPendingTx = false
if (uuid !== d.uuid) return if (uuid !== d.uuid) return
if (!!error) { if (!!error) {

View File

@ -58,14 +58,14 @@ QtObject {
return networksModule.getBlockExplorerURL(chainID) return networksModule.getBlockExplorerURL(chainID)
} }
function authenticateAndTransfer(uuid) { function authenticateAndTransfer(uuid, slippagePercentage = "") {
walletSectionSendInst.authenticateAndTransfer(uuid) walletSectionSendInst.authenticateAndTransfer(uuid, slippagePercentage)
} }
function suggestedRoutes(amountIn, amountOut = "0", extraParamsJson = "") { function suggestedRoutes(uuid, amountIn, amountOut = "0", extraParamsJson = "") {
const valueIn = AmountsArithmetic.fromNumber(amountIn) const valueIn = AmountsArithmetic.fromNumber(amountIn)
const valueOut = AmountsArithmetic.fromNumber(amountOut) const valueOut = AmountsArithmetic.fromNumber(amountOut)
walletSectionSendInst.suggestedRoutes(valueIn.toFixed(), valueOut.toFixed(), extraParamsJson) walletSectionSendInst.suggestedRoutes(uuid, valueIn.toFixed(), valueOut.toFixed(), extraParamsJson)
} }
function stopUpdatesForSuggestedRoute() { function stopUpdatesForSuggestedRoute() {

2
vendor/status-go vendored

@ -1 +1 @@
Subproject commit 2f71d9d9f2529cfa21cabb216be7992a5f9f6717 Subproject commit 107e2cb8daef1b89b5f6b8dac6f0aa70d901f711