diff --git a/src/app/modules/main/wallet_section/transactions/controller.nim b/src/app/modules/main/wallet_section/transactions/controller.nim index dd8f685e68..df2598f62e 100644 --- a/src/app/modules/main/wallet_section/transactions/controller.nim +++ b/src/app/modules/main/wallet_section/transactions/controller.nim @@ -3,10 +3,13 @@ import io_interface import ../../../../../app_service/service/transaction/service as transaction_service import ../../../../../app_service/service/network/service as network_service import ../../../../../app_service/service/wallet_account/service as wallet_account_service +import ../../../shared_modules/keycard_popup/io_interface as keycard_shared_module import ../../../../core/[main] import ../../../../core/tasks/[qt, threadpool] +const UNIQUE_WALLET_SECTION_TRANSACTION_MODULE_IDENTIFIER* = "WalletSection-TransactionModule" + type Controller* = ref object of RootObj delegate: io_interface.AccessInterface @@ -69,6 +72,12 @@ proc init*(self: Controller) = self.events.on(SIGNAL_TRANSACTION_SENT) do(e:Args): self.delegate.transactionWasSent(TransactionSentArgs(e).result) + self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args): + let args = SharedKeycarModuleArgs(e) + if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_TRANSACTION_MODULE_IDENTIFIER: + return + self.delegate.onUserAuthenticated(args.password) + proc checkPendingTransactions*(self: Controller) = self.transactionService.checkPendingTransactions() @@ -84,6 +93,9 @@ proc getWalletAccount*(self: Controller, accountIndex: int): WalletAccountDto = proc getAccountByAddress*(self: Controller, address: string): WalletAccountDto = self.walletAccountService.getAccountByAddress(address) +proc getMigratedKeyPairByKeyUid*(self: Controller, keyUid: string): seq[KeyPairDto] = + return self.walletAccountService.getMigratedKeyPairByKeyUid(keyUid) + proc loadTransactions*(self: Controller, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false) = self.transactionService.loadTransactions(address, toBlock, limit, loadMore) @@ -95,9 +107,8 @@ proc estimateGas*(self: Controller, from_addr: string, to: string, assetSymbol: proc transfer*(self: Controller, from_addr: string, to_addr: string, tokenSymbol: string, value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string,maxFeePerGas: string, - password: string, chainId: string, uuid: string, eip1559Enabled: bool, -): bool = - result = self.transactionService.transfer(from_addr, to_addr, tokenSymbol, value, gas, + password: string, chainId: string, uuid: string, eip1559Enabled: bool) = + discard self.transactionService.transfer(from_addr, to_addr, tokenSymbol, value, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas, password, chainId, uuid, eip1559Enabled) proc suggestedFees*(self: Controller, chainId: int): string = @@ -119,3 +130,11 @@ proc getEstimatedTime*(self: Controller, chainId: int, maxFeePerGas: string): Es proc getLastTxBlockNumber*(self: Controller): string = return self.transactionService.getLastTxBlockNumber(self.networkService.getNetworkForBrowser().chainId) + + +proc authenticateUser*(self: Controller, keyUid = "", bip44Path = "", txHash = "") = + let data = SharedKeycarModuleAuthenticationArgs(uniqueIdentifier: UNIQUE_WALLET_SECTION_TRANSACTION_MODULE_IDENTIFIER, + keyUid: keyUid, + bip44Path: bip44Path, + txHash: txHash) + self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data) \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/transactions/io_interface.nim b/src/app/modules/main/wallet_section/transactions/io_interface.nim index a7150884db..57a4094044 100644 --- a/src/app/modules/main/wallet_section/transactions/io_interface.nim +++ b/src/app/modules/main/wallet_section/transactions/io_interface.nim @@ -43,10 +43,13 @@ method setIsNonArchivalNode*(self: AccessInterface, isNonArchivalNode: bool) {.b method estimateGas*(self: AccessInterface, from_addr: string, to: string, assetSymbol: string, value: string, data: string): string {.base.} = raise newException(ValueError, "No implementation available") -method transfer*(self: AccessInterface, from_addr: string, to_addr: string, +method onUserAuthenticated*(self: AccessInterface, password: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method authenticateAndTransfer*(self: AccessInterface, from_addr: string, to_addr: string, tokenSymbol: string, value: string, gas: string, gasPrice: string, - maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, - chainId: string, uuid: string, eip1559Enabled: bool): bool {.base.} = + maxPriorityFeePerGas: string, maxFeePerGas: string, chainId: string, uuid: string, + eip1559Enabled: bool) {.base.} = raise newException(ValueError, "No implementation available") method transactionWasSent*(self: AccessInterface, result: string) {.base.} = diff --git a/src/app/modules/main/wallet_section/transactions/module.nim b/src/app/modules/main/wallet_section/transactions/module.nim index c68d1d27b4..5b2b086c72 100644 --- a/src/app/modules/main/wallet_section/transactions/module.nim +++ b/src/app/modules/main/wallet_section/transactions/module.nim @@ -10,12 +10,27 @@ import ../../../../../app_service/service/network/service as network_service export io_interface +# Shouldn't be public ever, user only within this module. +type TmpSendTransactionDetails = object + fromAddr: string + toAddr: string + tokenSymbol: string + value: string + gas: string + gasPrice: string + maxPriorityFeePerGas: string + maxFeePerGas: string + chainId: string + uuid: string + eip1559Enabled: bool + type Module* = ref object of io_interface.AccessInterface delegate: delegate_interface.AccessInterface view: View controller: Controller moduleLoaded: bool + tmpSendTransactionDetails: TmpSendTransactionDetails # Forward declarations method checkRecentHistory*(self: Module) @@ -90,11 +105,55 @@ method estimateGas*(self: Module, from_addr: string, to: string, assetSymbol: st method setIsNonArchivalNode*(self: Module, isNonArchivalNode: bool) = self.view.setIsNonArchivalNode(isNonArchivalNode) -method transfer*(self: Module, from_addr: string, to_addr: string, tokenSymbol: string, +method authenticateAndTransfer*(self: Module, from_addr: string, to_addr: string, tokenSymbol: string, value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, - maxFeePerGas: string, password: string, chainId: string, uuid: string, eip1559Enabled: bool): bool = - result = self.controller.transfer(from_addr, to_addr, tokenSymbol, value, gas, gasPrice, - maxPriorityFeePerGas, maxFeePerGas, password, chainId, uuid, eip1559Enabled) + maxFeePerGas: string, chainId: string, uuid: string, eip1559Enabled: bool) = + + self.tmpSendTransactionDetails.fromAddr = from_addr + self.tmpSendTransactionDetails.toAddr = to_addr + self.tmpSendTransactionDetails.tokenSymbol = tokenSymbol + self.tmpSendTransactionDetails.value = value + self.tmpSendTransactionDetails.gas = gas + self.tmpSendTransactionDetails.gasPrice = gasPrice + self.tmpSendTransactionDetails.maxPriorityFeePerGas = maxPriorityFeePerGas + self.tmpSendTransactionDetails.maxFeePerGas = maxFeePerGas + self.tmpSendTransactionDetails.chainId = chainId + self.tmpSendTransactionDetails.uuid = uuid + self.tmpSendTransactionDetails.eip1559Enabled = eip1559Enabled + + if singletonInstance.userProfile.getIsKeycardUser(): + let keyUid = singletonInstance.userProfile.getKeyUid() + self.controller.authenticateUser(keyUid) + else: + self.controller.authenticateUser() + + ################################## + ## Do Not Delete + ## + ## Once we start with signing a transactions we shold check if the address we want to send a transaction from is migrated + ## or not. In case it's not we should just authenticate logged in user, otherwise we should use one of the keycards that + ## address (key pair) is migrated to and sign the transaction using it. + ## + ## The code bellow is an example how we can achieve that in future, when we start with signing transactions. + ## + ## let acc = self.controller.getAccountByAddress(from_addr) + ## if acc.isNil: + ## echo "error: selected account to send a transaction from is not known" + ## return + ## let keyPair = self.controller.getMigratedKeyPairByKeyUid(acc.keyUid) + ## if keyPair.len == 0: + ## self.controller.authenticateUser() + ## else: + ## self.controller.authenticateUser(acc.keyUid, acc.path) + ## + ################################## + +method onUserAuthenticated*(self: Module, password: string) = + self.controller.transfer(self.tmpSendTransactionDetails.fromAddr, self.tmpSendTransactionDetails.toAddr, + self.tmpSendTransactionDetails.tokenSymbol, self.tmpSendTransactionDetails.value, self.tmpSendTransactionDetails.gas, + self.tmpSendTransactionDetails.gasPrice, self.tmpSendTransactionDetails.maxPriorityFeePerGas, + self.tmpSendTransactionDetails.maxFeePerGas, password, self.tmpSendTransactionDetails.chainId, self.tmpSendTransactionDetails.uuid, + self.tmpSendTransactionDetails.eip1559Enabled) method transactionWasSent*(self: Module, result: string) = self.view.transactionWasSent(result) diff --git a/src/app/modules/main/wallet_section/transactions/view.nim b/src/app/modules/main/wallet_section/transactions/view.nim index b96535ac81..f559d1d290 100644 --- a/src/app/modules/main/wallet_section/transactions/view.nim +++ b/src/app/modules/main/wallet_section/transactions/view.nim @@ -116,11 +116,11 @@ QtObject: proc transactionWasSent*(self: View,txResult: string) {.slot} = self.transactionSent(txResult) - proc transfer*(self: View, from_addr: string, to_addr: string, tokenSymbol: string, - value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, - maxFeePerGas: string, password: string, chainId: string, uuid: string, eip1559Enabled: bool): bool {.slot.} = - result = self.delegate.transfer(from_addr, to_addr, tokenSymbol, value, gas, gasPrice, - maxPriorityFeePerGas, maxFeePerGas, password, chainId, uuid, eip1559Enabled) + proc authenticateAndTransfer*(self: View, from_addr: string, to_addr: string, tokenSymbol: string, + value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, + maxFeePerGas: string, chainId: string, uuid: string, eip1559Enabled: bool) {.slot.} = + self.delegate.authenticateAndTransfer(from_addr, to_addr, tokenSymbol, value, gas, gasPrice, + maxPriorityFeePerGas, maxFeePerGas, chainId, uuid, eip1559Enabled) proc suggestedFees*(self: View, chainId: int): string {.slot.} = return self.delegate.suggestedFees(chainId) diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml index e3143ebc7e..cc63f717c9 100644 --- a/ui/app/AppLayouts/Chat/stores/RootStore.qml +++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml @@ -563,9 +563,9 @@ QtObject { } function transfer(from, to, address, tokenSymbol, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, chainId, uuid, eip1559Enabled) { - return walletSectionTransactions.transfer( + return walletSectionTransactions.authenticateAndTransfer( from, to, address, tokenSymbol, amount, gasLimit, - gasPrice, tipLimit, overallLimit, password, chainId, uuid, + gasPrice, tipLimit, overallLimit, chainId, uuid, eip1559Enabled ); } diff --git a/ui/app/AppLayouts/stores/RootStore.qml b/ui/app/AppLayouts/stores/RootStore.qml index 3b5a8ffd66..af6193c034 100644 --- a/ui/app/AppLayouts/stores/RootStore.qml +++ b/ui/app/AppLayouts/stores/RootStore.qml @@ -137,11 +137,10 @@ QtObject { return profileSectionStore.ensUsernamesStore.getGasEthValue(gweiValue, gasLimit) } - - function transfer(from, to, tokenSymbol, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, chainId, uuid, eip1559Enabled) { - return walletSectionTransactions.transfer( + function authenticateAndTransfer(from, to, tokenSymbol, amount, gasLimit, gasPrice, tipLimit, overallLimit, chainId, uuid, eip1559Enabled) { + walletSectionTransactions.authenticateAndTransfer( from, to, tokenSymbol, amount, gasLimit, - gasPrice, tipLimit, overallLimit, password, chainId, uuid, + gasPrice, tipLimit, overallLimit, chainId, uuid, eip1559Enabled ); } diff --git a/ui/imports/shared/popups/SendModal.qml b/ui/imports/shared/popups/SendModal.qml index d015215a2c..ea5c0943a1 100644 --- a/ui/imports/shared/popups/SendModal.qml +++ b/ui/imports/shared/popups/SendModal.qml @@ -38,9 +38,8 @@ StatusDialog { function sendTransaction() { let recipientAddress = Utils.isValidAddress(popup.addressText) ? popup.addressText : d.resolvedENSAddress - let success = false d.isPending = true - success = popup.store.transfer( + popup.store.authenticateAndTransfer( popup.selectedAccount.address, recipientAddress, assetSelector.selectedAsset.symbol, @@ -49,7 +48,6 @@ StatusDialog { gasSelector.suggestedFees.eip1559Enabled ? "" : gasSelector.selectedGasPrice, gasSelector.selectedTipLimit, gasSelector.selectedOverallLimit, - transactionSigner.enteredPassword, networkSelector.selectedNetwork.chainId, d.uuid, gasSelector.suggestedFees.eip1559Enabled, @@ -73,8 +71,7 @@ StatusDialog { }) enum StackGroup { - SendDetailsGroup = 0, - AuthenticationGroup = 1 + SendDetailsGroup = 0 } QtObject { @@ -484,19 +481,6 @@ StatusDialog { } } } - - Column{ - id: group2 - Layout.preferredWidth: parent.width - TransactionSigner { - id: transactionSigner - anchors.left: parent.left - anchors.right: parent.right - anchors.topMargin: Style.current.smallPadding - anchors.margins: 32 - signingPhrase: popup.store.signingPhrase - } - } } footer: SendModalFooter { @@ -506,10 +490,6 @@ StatusDialog { isLastGroup: d.isLastGroup visible: d.isReady && !isNaN(parseFloat(amountToSendInput.text)) && gasValidator.isValid onNextButtonClicked: { - if (isLastGroup) { - return popup.sendTransaction() - } - if(gasSelector.suggestedFees.eip1559Enabled && gasSelector.advancedMode){ if(gasSelector.showPriceLimitWarning || gasSelector.showTipLimitWarning){ Global.openPopup(transactionSettingsConfirmationPopupComponent, { @@ -523,13 +503,18 @@ StatusDialog { showPriceLimitWarning: gasSelector.showPriceLimitWarning, showTipLimitWarning: gasSelector.showTipLimitWarning, onConfirm: function(){ - stack.currentIndex = SendModal.StackGroup.AuthenticationGroup + if (isLastGroup) { + return popup.sendTransaction() + } } }) return } } - stack.currentIndex = SendModal.StackGroup.AuthenticationGroup + + if (isLastGroup) { + return popup.sendTransaction() + } } } @@ -547,10 +532,6 @@ StatusDialog { if (response.uuid !== d.uuid) return if (!response.success) { - if (Utils.isInvalidPasswordMessage(response.result)){ - transactionSigner.validationError = qsTr("Wrong password") - return - } sendingError.text = response.result return sendingError.open() }