diff --git a/src/app/modules/main/wallet_section/transactions/controller.nim b/src/app/modules/main/wallet_section/transactions/controller.nim index 4ce41c8947..8f7112bb1f 100644 --- a/src/app/modules/main/wallet_section/transactions/controller.nim +++ b/src/app/modules/main/wallet_section/transactions/controller.nim @@ -84,3 +84,9 @@ method transferEth*(self: Controller, from_addr: string, to_addr: string, value: password: string, uuid: string): bool = result = self.transactionService.transferEth(from_addr, to_addr, value, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas, password, uuid) + +method transferTokens*(self: Controller, from_addr: string, to_addr: string, contractAddress: string, + value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string,maxFeePerGas: string, + password: string, uuid: string): bool = + result = self.transactionService.transferTokens(from_addr, to_addr, contractAddress, value, gas, + gasPrice, maxPriorityFeePerGas, maxFeePerGas, password, uuid) diff --git a/src/app/modules/main/wallet_section/transactions/controller_interface.nim b/src/app/modules/main/wallet_section/transactions/controller_interface.nim index 97ffacd460..e778d89834 100644 --- a/src/app/modules/main/wallet_section/transactions/controller_interface.nim +++ b/src/app/modules/main/wallet_section/transactions/controller_interface.nim @@ -37,6 +37,12 @@ method transferEth*(self: AccessInterface, from_addr: string, to_addr: string, v password: string, uuid: string): bool {.base.} = raise newException(ValueError, "No implementation available") +method transferTokens*(self: AccessInterface, from_addr: string, to_addr: string, + contractAddress: string, value: string, gas: string, gasPrice: string, + maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, + uuid: string): bool {.base.} = + raise newException(ValueError, "No implementation available") + type ## Abstract class (concept) which must be implemented by object/s used in this ## module. 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 d0a7e61eb3..973ef5f913 100644 --- a/src/app/modules/main/wallet_section/transactions/io_interface.nim +++ b/src/app/modules/main/wallet_section/transactions/io_interface.nim @@ -48,6 +48,12 @@ method transferEth*(self: AccessInterface, from_addr: string, to_addr: string, v password: string, uuid: string): bool {.base.} = raise newException(ValueError, "No implementation available") +method transferTokens*(self: AccessInterface, from_addr: string, to_addr: string, + contractAddress: string, value: string, gas: string, gasPrice: string, + maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, + uuid: string): bool {.base.} = + raise newException(ValueError, "No implementation available") + # View Delegate Interface # Delegate for the view must be declared here due to use of QtObject and multi # inheritance, which is not well supported in Nim. diff --git a/src/app/modules/main/wallet_section/transactions/module.nim b/src/app/modules/main/wallet_section/transactions/module.nim index 01134e5196..a8de9f3efe 100644 --- a/src/app/modules/main/wallet_section/transactions/module.nim +++ b/src/app/modules/main/wallet_section/transactions/module.nim @@ -90,4 +90,10 @@ method transferEth*(self: Module, from_addr: string, to_addr: string, value: str gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, uuid: string): bool = result = self.controller.transferEth(from_addr, to_addr, value, gas, gasPrice, + maxPriorityFeePerGas, maxFeePerGas, password, uuid) + +method transferTokens*(self: Module, from_addr: string, to_addr: string, contractAddress: string, + value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, + maxFeePerGas: string, password: string, uuid: string): bool = + result = self.controller.transferTokens(from_addr, to_addr, contractAddress, value, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas, password, uuid) \ No newline at end of file diff --git a/src/app/modules/main/wallet_section/transactions/view.nim b/src/app/modules/main/wallet_section/transactions/view.nim index cf8fc59653..0cfbf8620d 100644 --- a/src/app/modules/main/wallet_section/transactions/view.nim +++ b/src/app/modules/main/wallet_section/transactions/view.nim @@ -105,9 +105,16 @@ QtObject: proc estimateGas*(self: View, from_addr: string, to: string, assetAddress: string, value: string, data: string): string {.slot.} = result = self.delegate.estimateGas(from_addr, to, assetAddress, value, data) + result = self.delegate.estimateGas(from_addr, to, assetAddress, value, data) proc transferEth*(self: View, from_addr: string, to_addr: string, value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, maxFeePerGas: string, password: string, uuid: string): bool {.slot.} = result = self.delegate.transferEth(from_addr, to_addr, value, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas, password, uuid) + + proc transferTokens*(self: View, from_addr: string, to_addr: string, contractAddress: string, + value: string, gas: string, gasPrice: string, maxPriorityFeePerGas: string, + maxFeePerGas: string, password: string, uuid: string): bool {.slot.} = + result = self.delegate.transferTokens(from_addr, to_addr, contractAddress, value, gas, gasPrice, + maxPriorityFeePerGas, maxFeePerGas, password, uuid) diff --git a/src/app_service/service/eth/dto/contract.nim b/src/app_service/service/eth/dto/contract.nim index 5e15ca2ce1..c1aec63c56 100644 --- a/src/app_service/service/eth/dto/contract.nim +++ b/src/app_service/service/eth/dto/contract.nim @@ -74,4 +74,4 @@ proc tokenSymbol*(contract: ContractDto): string = getTokenString(contract, "symbol") proc getMethod*(contract: ContractDto, methodName: string): MethodDto = - return contract.methods["methodName"] \ No newline at end of file + return contract.methods[methodName] \ No newline at end of file diff --git a/src/app_service/service/eth/dto/method_dto.nim b/src/app_service/service/eth/dto/method_dto.nim index 39a75278c7..dc89848d1e 100644 --- a/src/app_service/service/eth/dto/method_dto.nim +++ b/src/app_service/service/eth/dto/method_dto.nim @@ -93,7 +93,7 @@ proc send*(self: MethodDto, tx: var TransactionDataDto, methodDescriptor: object tx.data = self.encodeAbi(methodDescriptor) # this call should not be part of this file, we need to move it to appropriate place, or this should not be a DTO class. let response = status_eth.sendTransaction($(%tx), password) - return $response.result + return response.result.getStr proc call[T](self: MethodDto, tx: var TransactionDataDto, methodDescriptor: object, success: var bool): T = success = true diff --git a/src/app_service/service/transaction/service.nim b/src/app_service/service/transaction/service.nim index dd43e752a7..6378eb86b0 100644 --- a/src/app_service/service/transaction/service.nim +++ b/src/app_service/service/transaction/service.nim @@ -151,7 +151,8 @@ QtObject: value: string, data: string = "" ): string {.slot.} = - var response: RpcResponse[JsonNode] + var response: RpcResponse[JsonNode] + # TODO make this async try: if assetAddress != ZERO_ADDRESS and not assetAddress.isEmptyOrWhitespace: var tx = buildTokenTransaction( @@ -160,16 +161,17 @@ QtObject: ) let networkType = self.settingsService.getCurrentNetwork().toNetworkType() let network = self.networkService.getNetwork(networkType) - let contract = self.ethService.findErc20Contract(network.chainId, assetAddress) + let contract = self.ethService.findErc20Contract(network.chainId, parseAddress(assetAddress)) if contract == nil: raise newException(ValueError, fmt"Could not find ERC-20 contract with address '{assetAddress}' for the current network") let transfer = Transfer(to: parseAddress(to), value: conversion.eth2Wei(parseFloat(value), contract.decimals)) - let methodThing = contract.getMethod("transfer") + let transferMethod = contract.getMethod("transfer") var success: bool - let gas = methodThing.estimateGas(tx, transfer, success) + let gas = transferMethod.estimateGas(tx, transfer, success) - result = $(%* { "result": gas, "success": success }) + let res = fromHex[int](gas) + result = $(%* { "result": res, "success": success }) else: var tx = ens_utils.buildTransaction( parseAddress(from_addr), @@ -217,4 +219,43 @@ QtObject: except Exception as e: error "Error sending eth transfer transaction", msg = e.msg return false + return true + + proc transferTokens*( + self: Service, + from_addr: string, + to_addr: string, + assetAddress: string, + value: string, + gas: string, + gasPrice: string, + maxPriorityFeePerGas: string, + maxFeePerGas: string, + password: string, + uuid: string + ): bool = + try: + let eip1559Enabled = self.settingsService.isEIP1559Enabled() + eth_utils.validateTransactionInput(from_addr, to_addr, assetAddress, value, gas, + gasPrice, data = "", eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas, uuid) + + # TODO move this to another thread + let networkType = self.settingsService.getCurrentNetwork().toNetworkType() + let network = self.networkService.getNetwork(networkType) + let contract = self.eth_service.findErc20Contract(network.chainId, parseAddress(assetAddress)) + + var tx = ens_utils.buildTokenTransaction(parseAddress(from_addr), parseAddress(assetAddress), + gas, gasPrice, eip1559Enabled, maxPriorityFeePerGas, maxFeePerGas) + + var success: bool + let transfer = Transfer(to: parseAddress(to_addr), + value: conversion.eth2Wei(parseFloat(value), contract.decimals)) + let transferMethod = contract.getMethod("transfer") + let response = transferMethod.send(tx, transfer, password, success) + + self.trackPendingTransaction(response, from_addr, to_addr, + $PendingTransactionTypeDto.WalletTransfer, data = "") + except Exception as e: + error "Error sending token transfer transaction", msg = e.msg + return false return true \ No newline at end of file diff --git a/src/app_service/service/wallet_account/service.nim b/src/app_service/service/wallet_account/service.nim index c7c79f7d75..124f7b83a9 100644 --- a/src/app_service/service/wallet_account/service.nim +++ b/src/app_service/service/wallet_account/service.nim @@ -48,6 +48,10 @@ proc fetchPrice(crypto: string, fiat: string): float64 = client.headers = newHttpHeaders({ "Content-Type": "application/json" }) let response = client.request(url) + let parsedResponse = parseJson(response.body) + if (parsedResponse{"Response"} != nil and parsedResponse{"Response"}.getStr == "Error"): + error "Error while getting price", message = parsedResponse["Message"].getStr + return 0.0 result = parsefloat($parseJson(response.body)[fiat.toUpper]) priceCache[key] = result except Exception as e: diff --git a/ui/app/AppLayouts/stores/RootStore.qml b/ui/app/AppLayouts/stores/RootStore.qml index 88c45ba57a..ca75259802 100644 --- a/ui/app/AppLayouts/stores/RootStore.qml +++ b/ui/app/AppLayouts/stores/RootStore.qml @@ -73,4 +73,9 @@ QtObject { return walletSectionTransactions.transferEth(from, to, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, uuid); } + + function transferTokens(from, to, address, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, uuid) { + return walletSectionTransactions.transferTokens(from, to, address, amount, gasLimit, + gasPrice, tipLimit, overallLimit, password, uuid); + } } diff --git a/ui/imports/shared/popups/SendModal.qml b/ui/imports/shared/popups/SendModal.qml index 74ea0d30fc..bb35c2209b 100644 --- a/ui/imports/shared/popups/SendModal.qml +++ b/ui/imports/shared/popups/SendModal.qml @@ -51,18 +51,17 @@ ModalPopup { transactionSigner.enteredPassword, stack.uuid) } else { - // Not Refactored Yet - // success = RootStore.transferTokens( - // selectFromAccount.selectedAccount.address, - // selectRecipient.selectedRecipient.address, - // txtAmount.selectedAsset.address, - // txtAmount.selectedAmount, - // gasSelector.selectedGasLimit, - // gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice, - // gasSelector.selectedTipLimit, - // gasSelector.selectedOverallLimit, - // transactionSigner.enteredPassword, - // stack.uuid) + success = root.store.transferTokens( + selectFromAccount.selectedAccount.address, + selectRecipient.selectedRecipient.address, + txtAmount.selectedAsset.address, + txtAmount.selectedAmount, + gasSelector.selectedGasLimit, + gasSelector.eip1599Enabled ? "" : gasSelector.selectedGasPrice, + gasSelector.selectedTipLimit, + gasSelector.selectedOverallLimit, + transactionSigner.enteredPassword, + stack.uuid) } if(!success){ @@ -144,6 +143,7 @@ ModalPopup { id: txtAmount selectedAccount: selectFromAccount.selectedAccount currentCurrency: root.store.currentCurrency + // TODO make those use a debounce getFiatValue: root.store.getFiatValue // getCryptoValue: RootStore.cryptoValue width: stack.width diff --git a/ui/imports/shared/stores/RootStore.qml b/ui/imports/shared/stores/RootStore.qml index 05f6171465..b32ed3e8fc 100644 --- a/ui/imports/shared/stores/RootStore.qml +++ b/ui/imports/shared/stores/RootStore.qml @@ -62,14 +62,6 @@ QtObject { localAccountSensitiveSettings.isTenorWarningAccepted = value; } - function transferEth(from, to, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, uuid) { -// return walletModelInst.transactionsView.transferEth(from, to, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, uuid); - } - - function transferTokens(from, to, address, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, uuid) { -// return walletModelInst.transactionsView.transferTokens(from, to, address, amount, gasLimit, gasPrice, tipLimit, overallLimit, password, uuid); - } - function copyToClipboard(text) { globalUtils.copyToClipboard(text) }