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 = "wallet"
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"
NodeReady = "node.ready"
NodeCrashed = "node.crashed"

View File

@ -4,6 +4,7 @@ import base
import signal_type
import app_service/service/transaction/dtoV2
import app_service/service/transaction/router_transactions_dto
const SignTransactionsEventType* = "sing-transactions"
@ -25,6 +26,10 @@ type WalletSignal* = ref object of Signal
error*: string
errorCode*: string
updatedPrices*: Table[string, float64]
routerTransactionsSendingDetails*: SendDetailsDto
routerTransactionsForSigning*: RouterTransactionsForSigningDto
routerSentTransactions*: RouterSentTransactionsDto
transactionStatusChange*: TransactionStatusChange
proc fromEvent*(T: type WalletSignal, signalType: SignalType, jsonSignal: JsonNode): WalletSignal =
result = WalletSignal()
@ -54,6 +59,24 @@ proc fromEvent*(T: type WalletSignal, signalType: SignalType, jsonSignal: JsonNo
for tx in event:
result.txHashes.add(tx.getStr)
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:
try:
if event.contains("Uuid"):

View File

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

View File

@ -1,5 +1,5 @@
import Tables
import uuids, chronicles, options
import uuids, chronicles
import io_interface
import app_service/service/wallet_account/service as wallet_account_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_models/currency_amount
import app/core/signals/types
import app/core/eventemitter
logScope:
@ -56,11 +55,11 @@ proc delete*(self: Controller) =
proc init*(self: Controller) =
self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args):
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):
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):
let args = SharedKeycarModuleArgs(e)
@ -72,13 +71,13 @@ proc init*(self: Controller) =
let args = SuggestedRoutesArgs(e)
self.delegate.suggestedRoutesReady(args.uuid, args.suggestedRoutes, args.errCode, args.errDescription)
self.events.on(SignalType.WalletSignTransactions.event) do(e:Args):
var data = WalletSignal(e)
self.delegate.prepareSignaturesForTransactions(data.txHashes)
self.events.on(SIGNAL_SIGN_ROUTER_TRANSACTIONS) do(e:Args):
var data = RouterTransactionsForSigningArgs(e)
self.delegate.prepareSignaturesForTransactions(data.data)
self.events.on(SIGNAL_TRANSACTION_SENDING_COMPLETE) do(e:Args):
let args = TransactionMinedArgs(e)
self.delegate.transactionSendingComplete(args.transactionHash, args.success)
self.events.on(SIGNAL_TRANSACTION_STATUS_CHANGED) do(e:Args):
let args = TransactionStatusArgs(e)
self.delegate.transactionSendingComplete(args.data.hash, args.data.status)
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
return self.walletAccountService.getWalletAccounts()
@ -115,6 +114,7 @@ proc suggestedRoutes*(self: Controller,
accountFrom: string,
accountTo: string,
token: string,
tokenIsOwnerToken: bool,
amountIn: string,
toToken: string = "",
amountOut: string = "",
@ -122,23 +122,20 @@ proc suggestedRoutes*(self: Controller,
disabledToChainIDs: seq[int] = @[],
lockedInAmounts: 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)
proc stopSuggestedRoutesAsyncCalculation*(self: Controller) =
self.transactionService.stopSuggestedRoutesAsyncCalculation()
proc transfer*(self: Controller, from_addr: string, to_addr: 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]) =
self.transactionService.transfer(from_addr, to_addr, assetKey, toAssetKey, uuid, selectedRoutes, password, sendType,
usePassword, doHashing, tokenName, isOwnerToken, slippagePercentage)
proc buildTransactionsFromRoute*(self: Controller, uuid: string, slippagePercentage: float): string =
return self.transactionService.buildTransactionsFromRoute(uuid, slippagePercentage)
proc proceedWithTransactionsSignatures*(self: Controller, fromAddr: string, toAddr: string,
fromTokenKey: string, toTokenKey: string, uuid: string, signatures: TransactionsSignatures,
selectedRoutes: seq[TransactionPathDto], sendType: SendType) =
self.transactionService.proceedWithTransactionsSignatures(fromAddr, toAddr, fromTokenKey, toTokenKey, uuid, signatures, selectedRoutes, sendType)
proc signMessage*(self: Controller, address: string, hashedPassword: string, hashedMessage: string): tuple[res: string, err: string] =
return self.transactionService.signMessage(address, hashedPassword, hashedMessage)
proc sendRouterTransactionsWithSignatures*(self: Controller, uuid: string, signatures: TransactionsSignatures): string =
return self.transactionService.sendRouterTransactionsWithSignatures(uuid, signatures)
proc areTestNetworksEnabled*(self: Controller): bool =
return self.walletAccountService.areTestNetworksEnabled()
@ -159,7 +156,7 @@ proc connectKeycardReponseSignal(self: Controller) =
let currentFlow = self.keycardService.getCurrentFlow()
if currentFlow != KCSFlowType.Sign:
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
self.delegate.onTransactionSigned(args.flowType, args.flowEvent)

View File

@ -1,6 +1,7 @@
import Tables, options
import Tables
import app/modules/shared_models/currency_amount
import app_service/service/transaction/dto
import app_service/service/transaction/router_transactions_dto
import app_service/service/network/network_item
import app/modules/shared_models/collectibles_model as collectibles
from app_service/service/keycard/service import KeycardEvent
@ -27,6 +28,7 @@ method suggestedRoutes*(self: AccessInterface,
accountFrom: string,
accountTo: string,
token: string,
tokenIsOwnerToken: bool,
amountIn: string,
toToken: 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.} =
raise newException(ValueError, "No implementation available")
method authenticateAndTransfer*(self: AccessInterface, from_addr: string, to_addr: string, assetKey: string,
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.} =
method authenticateAndTransferV2*(self: AccessInterface, fromAddr: string, uuid: string, slippagePercentage: float) {.base.} =
raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string, pin: string) {.base.} =
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")
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.} =
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")
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.} =
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")
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 as delegate_interface
import app/global/global_singleton
import app/global/utils
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/network/service as network_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/constants as keycard_constants
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_service/service/network/network_item as network_service_item
@ -36,7 +37,7 @@ type TmpSendTransactionDetails = object
resolvedSignatures: TransactionsSignatures
tokenName: string
isOwnerToken: bool
slippagePercentage: Option[float]
slippagePercentage: float
type
Module* = ref object of io_interface.AccessInterface
@ -48,6 +49,7 @@ type
moduleLoaded: bool
tmpSendTransactionDetails: TmpSendTransactionDetails
tmpPin: string
tmpPassword: string
tmpTxHashBeingProcessed: string
# Forward declaration
@ -77,6 +79,13 @@ method delete*(self: Module) =
self.view.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 =
result = initNetworkRouteItem(
network.chainId,
@ -174,18 +183,10 @@ method getNetworkItem*(self: Module, chainId: int): network_service_item.Network
return nil
return networks[0]
method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string, assetKey: string, toAssetKey: string, uuid: string,
sendType: SendType, selectedTokenName: string, selectedTokenIsOwnerToken: bool) =
self.tmpSendTransactionDetails.fromAddr = fromAddr
self.tmpSendTransactionDetails.toAddr = toAddr
self.tmpSendTransactionDetails.assetKey = assetKey
self.tmpSendTransactionDetails.toAssetKey = toAssetKey
method authenticateAndTransferV2*(self: Module, fromAddr: string, uuid: string, slippagePercentage: float) =
self.tmpSendTransactionDetails.uuid = uuid
self.tmpSendTransactionDetails.sendType = sendType
self.tmpSendTransactionDetails.fromAddrPath = ""
self.tmpSendTransactionDetails.slippagePercentage = slippagePercentage
self.tmpSendTransactionDetails.resolvedSignatures.clear()
self.tmpSendTransactionDetails.tokenName = selectedTokenName
self.tmpSendTransactionDetails.isOwnerToken = selectedTokenIsOwnerToken
let kp = self.controller.getKeypairByAccountAddress(fromAddr)
if kp.migratedToKeycard():
@ -193,34 +194,36 @@ method authenticateAndTransfer*(self: Module, fromAddr: string, toAddr: string,
if accounts.len != 1:
error "cannot resolve selected account to send from among known keypair accounts"
return
self.tmpSendTransactionDetails.fromAddrPath = accounts[0].path
self.controller.authenticate(kp.keyUid)
else:
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) =
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:
self.tmpPin = pin
let doHashing = self.tmpPin.len == 0
let usePassword = self.tmpSendTransactionDetails.fromAddrPath.len == 0
self.controller.transfer(
self.tmpSendTransactionDetails.fromAddr, self.tmpSendTransactionDetails.toAddr,
self.tmpSendTransactionDetails.assetKey, self.tmpSendTransactionDetails.toAssetKey, self.tmpSendTransactionDetails.uuid,
self.tmpSendTransactionDetails.paths, password, self.tmpSendTransactionDetails.sendType, usePassword, doHashing,
self.tmpSendTransactionDetails.tokenName, self.tmpSendTransactionDetails.isOwnerToken, self.tmpSendTransactionDetails.slippagePercentage
)
self.tmpPassword = password
let err = self.controller.buildTransactionsFromRoute(self.tmpSendTransactionDetails.uuid, self.tmpSendTransactionDetails.slippagePercentage)
if err.len > 0:
self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = err)
self.clearTmpData()
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) =
self.tmpTxHashBeingProcessed = ""
@ -234,35 +237,70 @@ proc signOnKeycard(self: Module) =
self.controller.runSignFlow(self.tmpPin, self.tmpSendTransactionDetails.fromAddrPath, txForKcFlow)
break
if self.tmpTxHashBeingProcessed.len == 0:
self.controller.proceedWithTransactionsSignatures(self.tmpSendTransactionDetails.fromAddr, self.tmpSendTransactionDetails.toAddr,
self.tmpSendTransactionDetails.assetKey, self.tmpSendTransactionDetails.toAssetKey, self.tmpSendTransactionDetails.uuid,
self.tmpSendTransactionDetails.resolvedSignatures, self.tmpSendTransactionDetails.paths, self.tmpSendTransactionDetails.sendType)
self.sendSignedTransactions()
self.clearTmpData()
method prepareSignaturesForTransactions*(self: Module, txHashes: seq[string]) =
if txHashes.len == 0:
error "no transaction hashes to be signed"
return
for h in txHashes:
proc getRSVFromSignature(self: Module, signature: string): (string, string, string) =
let finalSignature = singletonInstance.utils.removeHexPrefix(signature)
if finalSignature.len != SIGNATURE_LEN:
return ("", "", "")
let r = finalSignature[0..63]
let s = finalSignature[64..127]
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) =
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
self.tmpSendTransactionDetails.resolvedSignatures[self.tmpTxHashBeingProcessed] = (keycardEvent.txSignature.r,
keycardEvent.txSignature.s, keycardEvent.txSignature.v)
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:
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
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) =
self.tmpSendTransactionDetails.paths = suggestedRoutes.best
self.tmpSendTransactionDetails.slippagePercentage = none(float)
self.tmpSendTransactionDetails.slippagePercentage = 0
let paths = suggestedRoutes.best.map(x => self.convertTransactionPathDtoToSuggestedRouteItem(x))
let suggestedRouteModel = newSuggestedRouteModel()
suggestedRouteModel.setItems(paths)
@ -286,6 +324,7 @@ method suggestedRoutes*(self: Module,
accountFrom: string,
accountTo: string,
token: string,
tokenIsOwnerToken: bool,
amountIn: string,
toToken: string = "",
amountOut: string = "",
@ -299,6 +338,7 @@ method suggestedRoutes*(self: Module,
accountFrom,
accountTo,
token,
tokenIsOwnerToken,
amountIn,
toToken,
amountOut,
@ -362,5 +402,5 @@ method splitAndFormatAddressPrefix*(self: Module, text : string, updateInStore:
editedText = "<a><p>" & editedText & "</a></p>"
return editedText
method transactionSendingComplete*(self: Module, txHash: string, success: bool) =
self.view.sendtransactionSendingCompleteSignal(txHash, success)
method transactionSendingComplete*(self: Module, txHash: string, status: string) =
self.view.sendtransactionSendingCompleteSignal(txHash, status)

View File

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

View File

@ -119,7 +119,10 @@ QtObject:
debug "signMessageWithCallback: signing on keycard started successfully"
return
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:
error "signMessageWithCallback failed: ", msg=e.msg
callback(topic, id, "", address, res)

View File

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

View File

@ -4,7 +4,6 @@
import stint
import ../../../backend/backend as backend
import ../../common/conversion as service_conversion
type
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/backend
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/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/token/service as token_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 ./dtoV2
import ./dto_conversion
import ./router_transactions_dto
import app_service/service/eth/utils as eth_utils
export transaction_dto
export transaction_dto, router_transactions_dto
export transactions.TransactionsSignatures
logScope:
@ -37,6 +36,8 @@ include async_tasks
include app_service/common/json_utils
# 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_SUGGESTED_ROUTES_READY* = "suggestedRoutesReady"
const SIGNAL_HISTORY_NON_ARCHIVAL_NODE* = "historyNonArchivalNode"
@ -44,12 +45,7 @@ const SIGNAL_HISTORY_ERROR* = "historyError"
const SIGNAL_TRANSACTION_DECODED* = "transactionDecoded"
const SIGNAL_OWNER_TOKEN_SENT* = "ownerTokenSent"
const SIGNAL_TRANSACTION_SENDING_COMPLETE* = "transactionSendingComplete"
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"
const SIGNAL_TRANSACTION_STATUS_CHANGED* = "transactionStatusChanged"
type TokenTransferMetadata* = object
tokenName*: string
@ -119,6 +115,10 @@ type
fromAmount*: string
toTokenKey*: string
toAmount*: string
approvalTx*: bool
username*: string
publicKey*: string
packId*: string
type
OwnerTokenSentArgs* = ref object of Args
@ -140,6 +140,18 @@ type
dataDecoded*: 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:
type Service* = ref object of QObject
events: EventEmitter
@ -151,6 +163,7 @@ QtObject:
## Forward declarations
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) =
self.QObject.delete
@ -184,6 +197,28 @@ QtObject:
self.tokenService.updateTokenPrices(data.updatedPrices)
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):
try:
var receivedData = TransactionMinedArgs(e)
@ -287,372 +322,55 @@ QtObject:
)
self.threadpool.start(arg)
proc createApprovalPath*(self: Service, route: TransactionPathDto, from_addr: string, toAddress: Address, gasFees: string): TransactionBridgeDto =
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) =
proc sendTransactionsSignal(self: Service, sendDetails: SendDetailsDto, sentTransactions: seq[RouterSentTransaction] = @[]) =
# 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)
# 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:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(uuid: uuid, error: err, txType: txType,
fromAddress: fromAddr, toAddress: toAddr, fromTokenKey: fromTokenKey, fromAmount: fromAmount,
toTokenKey: toTokenKey, toAmount: toAmount))
if txType == SendType.Swap:
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("swap", $(%*{"subEvent": "tx error"}))
elif response.result{"hashes"} != nil:
for route in routes:
for hash in response.result["hashes"][$route.fromNetwork.chainID]:
if isOwnerToken:
self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr,
uuid: uuid, tokenName: tokenName, status: ContractTransactionStatus.InProgress))
if not sendDetails.errorResponse.isNil and sendDetails.errorResponse.details.len > 0:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(
uuid: sendDetails.uuid,
error: sendDetails.errorResponse.details,
txType: SendType(sendDetails.sendType),
fromAddress: sendDetails.fromAddress,
toAddress: sendDetails.toAddress,
fromTokenKey: sendDetails.fromToken,
fromAmount: sendDetails.fromAmount.toString(10),
toTokenKey: sendDetails.toToken,
toAmount: sendDetails.toAmount.toString(10),
username: sendDetails.username,
publicKey: sendDetails.publicKey,
packId: sendDetails.packId
))
return
for tx in sentTransactions:
if sendDetails.ownerTokenBeingSent:
self.events.emit(SIGNAL_OWNER_TOKEN_SENT, OwnerTokenSentArgs(
chainId: tx.fromChain,
txHash: tx.hash,
uuid: sendDetails.uuid,
tokenName: tx.fromToken,
status: ContractTransactionStatus.InProgress
))
else:
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(chainId: route.fromNetwork.chainID, txHash: hash.getStr, uuid: uuid ,
error: "", txType: txType, fromAddress: fromAddr, toAddress: toAddr, fromTokenKey: fromTokenKey, fromAmount: fromAmount, toTokenKey: toTokenKey, toAmount: toAmount))
let metadata = TokenTransferMetadata(tokenName: tokenName, isOwnerToken: isOwnerToken)
self.watchTransaction(hash.getStr, fromAddr, toAddr, $PendingTransactionTypeDto.WalletTransfer, $(%metadata), route.fromNetwork.chainID,
fromTokenKey, fromAmount, toTokenKey, toAmount, txType)
if txType == SendType.Swap:
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("swap", $(%*{"subEvent": "tx success"}))
proc isCollectiblesTransfer(self: Service, sendType: SendType): bool =
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:
error "Invalid assetKey for collectibles transfer", assetKey=assetKey
return
try:
for route in routes:
var txData = TransactionDataDto()
var gasFees: string = ""
# If not collectible ...
if not asset.isNil:
var foundAddress = false
for addressPerChain in asset.addressPerChainId:
if addressPerChain.chainId == route.fromNetwork.chainId:
toContractAddress = parseAddress(addressPerChain.address)
foundAddress = true
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}")
self.events.emit(SIGNAL_TRANSACTION_SENT, TransactionSentArgs(
chainId: tx.fromChain,
txHash: tx.hash,
uuid: sendDetails.uuid,
txType: SendType(sendDetails.sendType),
fromAddress: tx.fromAddress,
toAddress: tx.toAddress,
fromTokenKey: tx.fromToken,
fromAmount: tx.amount.toString(10),
toTokenKey: tx.toToken,
toAmount: tx.amount.toString(10),
approvalTx: tx.approvalTx,
username: sendDetails.username,
publicKey: sendDetails.publicKey,
packId: sendDetails.packId
))
proc suggestedFees*(self: Service, chainId: int): SuggestedFeesDto =
try:
@ -688,6 +406,7 @@ QtObject:
accountFrom: string,
accountTo: string,
token: string,
tokenIsOwnerToken: bool,
amountIn: string,
toToken: string = "",
amountOut: string = "",
@ -706,7 +425,7 @@ QtObject:
try:
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:
error "suggestedRoutes", exception=e.msg
@ -747,3 +466,38 @@ proc getMultiTransactions*(transactionIDs: seq[int]): seq[MultiTransactionDto] =
let errDescription = e.msg
error "error: ", errDescription
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 hashRes.result.getStr()
proc signMessage*(self: Service, address: string, hashedPassword: string, hashedMessage: string): string =
var signMsgRes: JsonNode
let err = wallet.signMessage(signMsgRes,
hashedMessage,
address,
hashedPassword)
if err.len > 0:
error "status-go - wallet_signMessage failed", err=err
return signMsgRes.getStr
proc signMessage*(self: Service, address: string, hashedPassword: string, hashedMessage: string): tuple[res: string, err: string] =
return self.transactions.signMessage(address, hashedPassword, hashedMessage)
proc buildTransaction*(self: Service, chainId: int, txJson: string): tuple[txToSign: string, txData: 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)
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 =
let data = %* {
@ -50,6 +50,7 @@ proc prepareDataForSuggestedRoutes(uuid: string, sendType: int, accountFrom: str
"amountIn": amountIn,
"amountOut": amountOut,
"tokenID": token,
"tokenIDIsOwnerToken": tokenIsOwnerToken,
"toTokenID": toToken,
"disabledFromChainIDs": disabledFromChainIDs,
"disabledToChainIDs": disabledToChainIDs,
@ -69,19 +70,19 @@ proc prepareDataForSuggestedRoutes(uuid: string, sendType: int, accountFrom: str
return %* [data]
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].} =
let payload = prepareDataForSuggestedRoutes(uuid = "", sendType, accountFrom, accountTo, amountIn, amountOut, token, toToken, disabledFromChainIDs,
disabledToChainIDs, lockedInAmounts, extraParamsTable)
let payload = prepareDataForSuggestedRoutes(uuid = "", sendType, accountFrom, accountTo, amountIn, amountOut, token, tokenIsOwnerToken, toToken,
disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable)
if payload.isNil:
raise newException(RpcException, "Invalid key in extraParamsTable")
return core.callPrivateRPC("wallet_getSuggestedRoutes", payload)
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].} =
let payload = prepareDataForSuggestedRoutes(uuid, sendType, accountFrom, accountTo, amountIn, amountOut, token, toToken, disabledFromChainIDs,
disabledToChainIDs, lockedInAmounts, extraParamsTable)
let payload = prepareDataForSuggestedRoutes(uuid, sendType, accountFrom, accountTo, amountIn, amountOut, token, tokenIsOwnerToken, toToken,
disabledFromChainIDs, disabledToChainIDs, lockedInAmounts, extraParamsTable)
if payload.isNil:
raise newException(RpcException, "Invalid key in extraParamsTable")
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
include common
type
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] =
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] =
let payload = %* [transactionIDs]
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] =
let payload = %* [chainId, hash]
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
include common
rpc(signMessage, "wallet"):
message: string
address: string
@ -24,17 +26,6 @@ rpc(sendTransactionWithSignature, "wallet"):
sendTxArgsJson: 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`
## `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
signal suggestedRoutesReady(var txRoutes, string errCode, string errDescription)
signal transactionSent(var chainId, var txHash, var uuid, var error)
signal transactionSendingComplete(var txHash, var success)
signal transactionSendingComplete(var txHash, var status)
}
walletAssetsStore: WalletAssetsStore {
id: thisWalletAssetStore

View File

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

View File

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

View File

@ -39,17 +39,6 @@ StatusDialog {
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() {
if (root.swapInputParamsForm.isFormFilledCorrectly()) {
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
Binding {
target: root.swapAdaptor

View File

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

View File

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

View File

@ -78,7 +78,7 @@ StatusDialog {
popup.isLoading = true
d.routerError = ""
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
}
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
if (uuid !== d.uuid) return
if (!!error) {

View File

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

2
vendor/status-go vendored

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