chore: sign the flow only once if approval and transaction need to be placed once after another (swap flow)

Closes #16337
This commit is contained in:
Sale Djenic 2024-10-08 17:28:33 +02:00 committed by saledjenic
parent 684d0b4d63
commit fe5c135486
10 changed files with 60 additions and 56 deletions

View File

@ -44,7 +44,7 @@ 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 authenticateAndTransferV2*(self: AccessInterface, fromAddr: string, uuid: string, slippagePercentage: float) {.base.} =
method authenticateAndTransfer*(self: AccessInterface, fromAddr: string, uuid: string, slippagePercentage: float) {.base.} =
raise newException(ValueError, "No implementation available")
method onUserAuthenticated*(self: AccessInterface, password: string, pin: string) {.base.} =

View File

@ -26,17 +26,13 @@ const authenticationCanceled* = "authenticationCanceled"
# Shouldn't be public ever, use only within this module.
type TmpSendTransactionDetails = object
fromAddr: string
fromAddrPath: string
toAddr: string
assetKey: string
toAssetKey: string
paths: seq[TransactionPathDto]
uuid: string
sendType: SendType
pin: string
password: string
txHashBeingProcessed: string
resolvedSignatures: TransactionsSignatures
tokenName: string
isOwnerToken: bool
slippagePercentage: float
type
@ -48,9 +44,7 @@ type
controller: controller.Controller
moduleLoaded: bool
tmpSendTransactionDetails: TmpSendTransactionDetails
tmpPin: string
tmpPassword: string
tmpTxHashBeingProcessed: string
tmpKeepPinPass: bool
# Forward declaration
method getTokenBalance*(self: Module, address: string, chainId: int, tokensKey: string): CurrencyAmount
@ -79,12 +73,15 @@ method delete*(self: Module) =
self.view.delete
self.controller.delete
proc clearTmpData(self: Module) =
self.tmpPin = ""
self.tmpPassword = ""
self.tmpTxHashBeingProcessed = ""
proc clearTmpData(self: Module, keepPinPass = false) =
if keepPinPass:
self.tmpSendTransactionDetails = TmpSendTransactionDetails(
sendType: self.tmpSendTransactionDetails.sendType,
pin: self.tmpSendTransactionDetails.pin,
password: self.tmpSendTransactionDetails.password
)
return
self.tmpSendTransactionDetails = TmpSendTransactionDetails()
writeStackTrace()
proc convertSendToNetworkToNetworkItem(self: Module, network: SendToNetwork): NetworkRouteItem =
result = initNetworkRouteItem(
@ -183,11 +180,22 @@ method getNetworkItem*(self: Module, chainId: int): network_service_item.Network
return nil
return networks[0]
method authenticateAndTransferV2*(self: Module, fromAddr: string, uuid: string, slippagePercentage: float) =
proc buildTransactionsFromRoute(self: Module) =
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()
method authenticateAndTransfer*(self: Module, fromAddr: string, uuid: string, slippagePercentage: float) =
self.tmpSendTransactionDetails.uuid = uuid
self.tmpSendTransactionDetails.slippagePercentage = slippagePercentage
self.tmpSendTransactionDetails.resolvedSignatures.clear()
if self.tmpKeepPinPass:
# no need to authenticate again, just send a swap tx
self.buildTransactionsFromRoute()
return
let kp = self.controller.getKeypairByAccountAddress(fromAddr)
if kp.migratedToKeycard():
let accounts = kp.accounts.filter(acc => cmpIgnoreCase(acc.address, fromAddr) == 0)
@ -203,12 +211,9 @@ method onUserAuthenticated*(self: Module, password: string, pin: string) =
self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = authenticationCanceled)
self.clearTmpData()
else:
self.tmpPin = pin
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()
self.tmpSendTransactionDetails.pin = pin
self.tmpSendTransactionDetails.password = password
self.buildTransactionsFromRoute()
proc sendSignedTransactions*(self: Module) =
try:
@ -226,17 +231,17 @@ proc sendSignedTransactions*(self: Module) =
self.clearTmpData()
proc signOnKeycard(self: Module) =
self.tmpTxHashBeingProcessed = ""
self.tmpSendTransactionDetails.txHashBeingProcessed = ""
for h, (r, s, v) in self.tmpSendTransactionDetails.resolvedSignatures.pairs:
if r.len != 0 and s.len != 0 and v.len != 0:
continue
self.tmpTxHashBeingProcessed = h
var txForKcFlow = self.tmpTxHashBeingProcessed
self.tmpSendTransactionDetails.txHashBeingProcessed = h
var txForKcFlow = self.tmpSendTransactionDetails.txHashBeingProcessed
if txForKcFlow.startsWith("0x"):
txForKcFlow = txForKcFlow[2..^1]
self.controller.runSignFlow(self.tmpPin, self.tmpSendTransactionDetails.fromAddrPath, txForKcFlow)
self.controller.runSignFlow(self.tmpSendTransactionDetails.pin, self.tmpSendTransactionDetails.fromAddrPath, txForKcFlow)
break
if self.tmpTxHashBeingProcessed.len == 0:
if self.tmpSendTransactionDetails.txHashBeingProcessed.len == 0:
self.sendSignedTransactions()
self.clearTmpData()
@ -265,7 +270,7 @@ method prepareSignaturesForTransactions*(self:Module, txForSigning: RouterTransa
self.tmpSendTransactionDetails.resolvedSignatures[h] = ("", "", "")
self.signOnKeycard()
else:
let finalPassword = hashPassword(self.tmpPassword)
let finalPassword = hashPassword(self.tmpSendTransactionDetails.password)
for h in txForSigning.signingDetails.hashes:
self.tmpSendTransactionDetails.resolvedSignatures[h] = ("", "", "")
var
@ -288,19 +293,18 @@ method onTransactionSigned*(self: Module, keycardFlowType: string, keycardEvent:
self.transactionWasSent(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error = err)
self.clearTmpData()
return
self.tmpSendTransactionDetails.resolvedSignatures[self.tmpTxHashBeingProcessed] = (keycardEvent.txSignature.r,
self.tmpSendTransactionDetails.resolvedSignatures[self.tmpSendTransactionDetails.txHashBeingProcessed] = (keycardEvent.txSignature.r,
keycardEvent.txSignature.s, keycardEvent.txSignature.v)
self.signOnKeycard()
method transactionWasSent*(self: Module, uuid: string, chainId: int = 0, approvalTx: bool = false, txHash: string = "", error: string = "") =
self.tmpKeepPinPass = approvalTx # need to automate the swap flow with approval
if txHash.len == 0:
self.view.sendTransactionSentSignal(uuid = self.tmpSendTransactionDetails.uuid, chainId = 0, approvalTx = false, txHash = "", error)
return
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 = 0
let paths = suggestedRoutes.best.map(x => self.convertTransactionPathDtoToSuggestedRouteItem(x))
let suggestedRouteModel = newSuggestedRouteModel()
suggestedRouteModel.setItems(paths)
@ -332,6 +336,7 @@ method suggestedRoutes*(self: Module,
disabledToChainIDs: seq[int] = @[],
lockedInAmounts: Table[string, string] = initTable[string, string](),
extraParamsTable: Table[string, string] = initTable[string, string]()) =
self.tmpSendTransactionDetails.sendType = sendType
self.controller.suggestedRoutes(
uuid,
sendType,
@ -403,4 +408,5 @@ method splitAndFormatAddressPrefix*(self: Module, text : string, updateInStore:
return editedText
method transactionSendingComplete*(self: Module, txHash: string, status: string) =
self.clearTmpData(self.tmpKeepPinPass)
self.view.sendtransactionSendingCompleteSignal(txHash, status)

View File

@ -180,7 +180,7 @@ QtObject:
slippagePercentage = slippagePercentageString.parseFloat()
except:
error "parsing slippage failed", slippage=slippagePercentageString
self.delegate.authenticateAndTransferV2(self.selectedSenderAccountAddress, uuid, slippagePercentage)
self.delegate.authenticateAndTransfer(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) =

View File

@ -129,7 +129,6 @@ QtObject:
break
if ensDto.username.len == 0:
error "Error updating ens username status", message = "no ens username found for transactionHash: " & transactionHash
return
let key = makeKey(ensDto.username, chainId)

View File

@ -363,6 +363,8 @@ Item {
verify(!!headerContentItemEmoji)
compare(headerContentItemEmoji.asset.emoji, swapAdaptor.nonWatchAccounts.get(i).emoji)
waitForRendering(amountToSendInput)
verify(amountToSendInput.cursorVisible)
}
closeAndVerfyModal()
@ -1399,6 +1401,7 @@ Item {
launchAndVerfyModal()
waitForRendering(payPanel)
waitForRendering(receivePanel)
waitForRendering(payAmountToSendInput)
let paytokenSelectorContentItemText = findChild(payPanel, "tokenSelectorContentItemText")
verify(!!paytokenSelectorContentItemText)

View File

@ -99,8 +99,7 @@ Item {
controlUnderTest.toTokenAmount = "1.42"
controlUnderTest.toTokenContractAddress = "0xdeadcaff"
// title & subtitle
compare(controlUnderTest.title, qsTr("Sign Swap"))
// subtitle
compare(controlUnderTest.subtitle, qsTr("%1 to %2").arg(controlUnderTest.formatBigNumber(controlUnderTest.fromTokenAmount, controlUnderTest.fromTokenSymbol))
.arg(controlUnderTest.formatBigNumber(controlUnderTest.toTokenAmount, controlUnderTest.toTokenSymbol)))

View File

@ -36,8 +36,12 @@ StatusDialog {
property Component headerIconComponent
property bool feesLoading
property string signButtonText: qsTr("Sign")
property bool signButtonEnabled: true
property string closeButtonText: qsTr("Close")
property date requestTimestamp: new Date()
property int expirationSeconds
property bool hasExpiryDate: false
@ -61,14 +65,14 @@ StatusDialog {
visible: !root.hasExpiryDate || !countdownPill.isExpired
icon.name: Constants.authenticationIconByType[root.loginType]
disabledColor: Theme.palette.directColor8
text: qsTr("Sign")
text: root.signButtonText
onClicked: root.accept() // close and emit accepted() signal
}
StatusButton {
objectName: "closeButton"
id: closeButton
visible: root.hasExpiryDate && countdownPill.isExpired
text: qsTr("Close")
text: root.closeButtonText
onClicked: root.close()
}
}

View File

@ -397,10 +397,12 @@ StatusDialog {
: Constants.authenticationIconByType[root.loginType]
text: {
if(root.swapAdaptor.validSwapProposalReceived) {
if (root.swapAdaptor.approvalPending) {
return qsTr("Approving %1").arg(fromTokenSymbol)
} else if(root.swapAdaptor.swapOutputData.approvalNeeded) {
return qsTr("Approve %1").arg(fromTokenSymbol)
if(root.swapAdaptor.swapOutputData.approvalNeeded) {
if (root.swapAdaptor.approvalPending) {
return qsTr("Approving %1").arg(fromTokenSymbol)
} else if(!root.swapAdaptor.approvalSuccessful) {
return qsTr("Approve %1").arg(fromTokenSymbol)
}
}
}
return qsTr("Swap")
@ -416,7 +418,7 @@ StatusDialog {
onClicked: {
if (root.swapAdaptor.validSwapProposalReceived) {
d.addMetricsEvent("next button pressed")
if (root.swapAdaptor.swapOutputData.approvalNeeded)
if (root.swapAdaptor.swapOutputData.approvalNeeded && !root.swapAdaptor.approvalSuccessful)
Global.openPopup(swapApproveModalComponent)
else
Global.openPopup(swapSignModalComponent)
@ -483,6 +485,9 @@ StatusDialog {
SwapSignModal {
destroyOnClose: true
title: root.swapAdaptor.swapOutputData.approvalNeeded && root.swapAdaptor.approvalSuccessful? qsTr("Swap") : qsTr("Sign Swap")
signButtonText: root.swapAdaptor.swapOutputData.approvalNeeded && root.swapAdaptor.approvalSuccessful? qsTr("Swap") : qsTr("Sign")
formatBigNumber: (number, symbol, noSymbolOption) => root.swapAdaptor.currencyStore.formatBigNumber(number, symbol, noSymbolOption)
loginType: root.swapAdaptor.selectedAccount.migratedToKeycard ? Constants.LoginType.Keycard : root.loginType

View File

@ -87,8 +87,6 @@ QObject {
readonly property bool isEthBalanceInsufficient: d.isEthBalanceInsufficient
readonly property bool isTokenBalanceInsufficient: d.isTokenBalanceInsufficient
signal suggestedRoutesReady()
QtObject {
id: d
@ -252,11 +250,10 @@ QObject {
root.swapOutputData.hasError = true
}
root.swapOutputData.hasError = root.swapOutputData.hasError || root.swapOutputData.errCode !== ""
root.suggestedRoutesReady()
}
function onTransactionSent(uuid, chainId, approvalTx, txHash, error) {
if(root.swapOutputData.approvalNeeded) {
if(root.swapOutputData.approvalNeeded && !root.approvalSuccessful) {
if (uuid !== d.uuid || !!error) {
root.approvalPending = false
root.approvalSuccessful = false
@ -272,10 +269,6 @@ QObject {
root.approvalPending = false
root.approvalSuccessful = status == "Success" // TODO: make a all tx statuses Constants (success, pending, failed)
d.txHash = ""
if (root.approvalSuccessful) {
root.swapOutputData.approvalNeeded = false
}
}
}
}
@ -335,14 +328,10 @@ QObject {
function sendApproveTx() {
root.approvalPending = true
const accountAddress = root.swapFormData.selectedAccountAddress
root.swapStore.authenticateAndTransfer(d.uuid, "")
}
function sendSwapTx() {
const accountAddress = root.swapFormData.selectedAccountAddress
root.swapStore.authenticateAndTransfer(d.uuid, root.swapFormData.selectedSlippage)
}
}

View File

@ -45,7 +45,6 @@ SignTransactionModalBase {
required property string serviceProviderURL
required property string serviceProviderTandCUrl
title: qsTr("Sign Swap")
//: e.g. (swap) 100 DAI to 100 USDT
subtitle: qsTr("%1 to %2").arg(formatBigNumber(fromTokenAmount, fromTokenSymbol)).arg(formatBigNumber(toTokenAmount, toTokenSymbol))