fix(browser-tx): fix estimate gas and send TX on the browser
Fixes #4557
This commit is contained in:
parent
6f5fcd8623
commit
82fb325dac
|
@ -142,7 +142,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
|
|||
result.walletAccountService = wallet_account_service.newService(statusFoundation.events, result.settingsService,
|
||||
result.accountsService, result.tokenService)
|
||||
result.transactionService = transaction_service.newService(statusFoundation.events, statusFoundation.threadpool,
|
||||
result.walletAccountService)
|
||||
result.walletAccountService, result.ethService, result.networkService, result.settingsService)
|
||||
result.bookmarkService = bookmark_service.newService()
|
||||
result.profileService = profile_service.newService()
|
||||
result.stickersService = stickers_service.newService(
|
||||
|
|
|
@ -75,3 +75,6 @@ method getAccountByAddress*(self: Controller, address: string): WalletAccountDto
|
|||
|
||||
method loadTransactions*(self: Controller, address: string, toBlock: Uint256, limit: int = 20, loadMore: bool = false) =
|
||||
self.transactionService.loadTransactions(address, toBlock, limit, loadMore)
|
||||
|
||||
method estimateGas*(self: Controller, from_addr: string, to: string, assetAddress: string, value: string, data: string): string =
|
||||
result = self.transactionService.estimateGas(from_addr, to, assetAddress, value, data)
|
||||
|
|
|
@ -29,6 +29,9 @@ method loadTransactions*(self: AccessInterface, address: string, toBlock: Uint25
|
|||
method setTrxHistoryResult*(self: AccessInterface, historyJSON: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method estimateGas*(self: AccessInterface, from_addr: string, to: string, assetAddress: string, value: string, data: string): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
type
|
||||
## Abstract class (concept) which must be implemented by object/s used in this
|
||||
## module.
|
||||
|
|
|
@ -40,6 +40,9 @@ method setHistoryFetchState*(self: AccessInterface, addresses: seq[string], isFe
|
|||
method setIsNonArchivalNode*(self: AccessInterface, isNonArchivalNode: bool) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method estimateGas*(self: AccessInterface, from_addr: string, to: string, assetAddress: string, value: string, data: string): string {.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.
|
||||
|
|
|
@ -80,5 +80,8 @@ method setTrxHistoryResult*(self: Module, transactions: seq[TransactionDto], add
|
|||
method setHistoryFetchState*(self: Module, addresses: seq[string], isFetching: bool) =
|
||||
self.view.setHistoryFetchStateForAccounts(addresses, isFetching)
|
||||
|
||||
method estimateGas*(self: Module, from_addr: string, to: string, assetAddress: string, value: string, data: string): string =
|
||||
result = self.controller.estimateGas(from_addr, to, assetAddress, value, data)
|
||||
|
||||
method setIsNonArchivalNode*(self: Module, isNonArchivalNode: bool) =
|
||||
self.view.setIsNonArchivalNode(isNonArchivalNode)
|
|
@ -103,3 +103,6 @@ QtObject:
|
|||
read = getIsNonArchivalNode
|
||||
notify = isNonArchivalNodeChanged
|
||||
|
||||
|
||||
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)
|
||||
|
|
|
@ -186,8 +186,16 @@ proc owner*(username: string): string =
|
|||
return ""
|
||||
result = "0x" & ownerAddr.substr(26)
|
||||
|
||||
proc buildTransaction*(source: Address, value: Uint256, gas = "", gasPrice = "", isEIP1559Enabled = false,
|
||||
maxPriorityFeePerGas = "", maxFeePerGas = "", data = ""): TransactionDataDto =
|
||||
proc buildTransaction*(
|
||||
source: Address,
|
||||
value: Uint256,
|
||||
gas = "",
|
||||
gasPrice = "",
|
||||
isEIP1559Enabled = false,
|
||||
maxPriorityFeePerGas = "",
|
||||
maxFeePerGas = "",
|
||||
data = ""
|
||||
): TransactionDataDto =
|
||||
result = TransactionDataDto(
|
||||
source: source,
|
||||
value: value.some,
|
||||
|
|
|
@ -71,4 +71,7 @@ proc tokenName*(contract: ContractDto): string =
|
|||
getTokenString(contract, "name")
|
||||
|
||||
proc tokenSymbol*(contract: ContractDto): string =
|
||||
getTokenString(contract, "symbol")
|
||||
getTokenString(contract, "symbol")
|
||||
|
||||
proc getMethod*(contract: ContractDto, methodName: string): MethodDto =
|
||||
return contract.methods["methodName"]
|
|
@ -9,7 +9,10 @@ import ../ens/utils as ens_utils
|
|||
import service_interface
|
||||
import status/permissions as status_go_permissions
|
||||
import status/core as status_go_core
|
||||
import status/eth as status_eth
|
||||
import ../../common/utils as status_utils
|
||||
import ../eth/utils as eth_utils
|
||||
import ../eth/dto/transaction as transaction_data_dto
|
||||
from stew/base32 import nil
|
||||
from stew/base58 import nil
|
||||
import stew/byteutils
|
||||
|
@ -134,17 +137,13 @@ proc process(self: Service, data: Web3SendAsyncReadOnly): string =
|
|||
|
||||
var success: bool
|
||||
var errorMessage = ""
|
||||
var response = ""
|
||||
var response: RpcResponse[JsonNode]
|
||||
var validInput: bool = true
|
||||
|
||||
|
||||
# TODO: use the transaction service to send the trx
|
||||
|
||||
#[
|
||||
let eip1559Enabled = self.wallet.isEIP1559Enabled()
|
||||
let eip1559Enabled: bool = self.settingsService.isEIP1559Enabled()
|
||||
|
||||
try:
|
||||
validateTransactionInput(fromAddress, to, "", value, selectedGasLimit, selectedGasPrice, txData, eip1559Enabled, selectedTipLimit, selectedOverallLimit, "dummy")
|
||||
eth_utils.validateTransactionInput(fromAddress, to, "", value, selectedGasLimit, selectedGasPrice, txData, eip1559Enabled, selectedTipLimit, selectedOverallLimit, "dummy")
|
||||
except Exception as e:
|
||||
validInput = false
|
||||
success = false
|
||||
|
@ -152,39 +151,43 @@ proc process(self: Service, data: Web3SendAsyncReadOnly): string =
|
|||
|
||||
if validInput:
|
||||
# TODO make this async
|
||||
response = wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, eip1559Enabled, selectedTipLimit, selectedOverallLimit, password, success, txData)
|
||||
errorMessage = if not success:
|
||||
if response == "":
|
||||
"web3-response-error"
|
||||
var tx = ens_utils.buildTransaction(
|
||||
parseAddress(fromAddress),
|
||||
eth2Wei(parseFloat(value), 18),
|
||||
selectedGasLimit,
|
||||
selectedGasPrice,
|
||||
eip1559Enabled,
|
||||
selectedTipLimit,
|
||||
selectedOverallLimit,
|
||||
txData
|
||||
)
|
||||
tx.to = parseAddress(to).some
|
||||
|
||||
try:
|
||||
# TODO: use the transaction service to send the trx
|
||||
let json: JsonNode = %tx
|
||||
response = status_eth.sendTransaction($json, password)
|
||||
if response.error != nil:
|
||||
success = false
|
||||
errorMessage = response.error.message
|
||||
else:
|
||||
response
|
||||
else:
|
||||
""
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": errorMessage,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": if (success): response else: ""
|
||||
}
|
||||
}
|
||||
|
||||
]#
|
||||
# TODO: delete this:
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": "",
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": ""
|
||||
}
|
||||
}
|
||||
success = true
|
||||
errorMessage = ""
|
||||
except Exception as e:
|
||||
error "Error sending transaction", msg = e.msg
|
||||
errorMessage = e.msg
|
||||
success = false
|
||||
|
||||
return $ %* {
|
||||
"type": ResponseTypes.Web3SendAsyncCallback,
|
||||
"messageId": data.messageId,
|
||||
"error": errorMessage,
|
||||
"result": {
|
||||
"jsonrpc": "2.0",
|
||||
"id": data.payload.id,
|
||||
"result": if (success): response.result.getStr else: ""
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
error "Error sending the transaction", msg = e.msg
|
||||
|
|
|
@ -1,12 +1,22 @@
|
|||
import NimQml, chronicles, sequtils, sugar, stint, strutils, json
|
||||
import NimQml, chronicles, sequtils, sugar, stint, strutils, json, strformat
|
||||
import status/transactions as transactions
|
||||
import status/wallet as status_wallet
|
||||
import status/eth
|
||||
|
||||
import ../ens/utils as ens_utils
|
||||
from ../../common/account_constants import ZERO_ADDRESS
|
||||
|
||||
import ../../../app/core/[main]
|
||||
import ../../../app/core/tasks/[qt, threadpool]
|
||||
import ../wallet_account/service as wallet_account_service
|
||||
import ../eth/service as eth_service
|
||||
import ../network/service as network_service
|
||||
import ../settings/service as settings_service
|
||||
import ../eth/dto/transaction as transaction_data_dto
|
||||
import ../eth/dto/[contract, method_dto]
|
||||
import ./dto as transaction_dto
|
||||
import ../eth/utils as eth_utils
|
||||
import ../../common/conversion
|
||||
|
||||
export transaction_dto
|
||||
|
||||
|
@ -37,16 +47,29 @@ QtObject:
|
|||
events: EventEmitter
|
||||
threadpool: ThreadPool
|
||||
walletAccountService: wallet_account_service.ServiceInterface
|
||||
ethService: eth_service.ServiceInterface
|
||||
networkService: network_service.ServiceInterface
|
||||
settingsService: settings_service.ServiceInterface
|
||||
|
||||
proc delete*(self: Service) =
|
||||
self.QObject.delete
|
||||
|
||||
proc newService*(events: EventEmitter, threadpool: ThreadPool, walletAccountService: wallet_account_service.ServiceInterface): Service =
|
||||
proc newService*(
|
||||
events: EventEmitter,
|
||||
threadpool: ThreadPool,
|
||||
walletAccountService: wallet_account_service.ServiceInterface,
|
||||
ethService: eth_service.ServiceInterface,
|
||||
networkService: network_service.ServiceInterface,
|
||||
settingsService: settings_service.ServiceInterface
|
||||
): Service =
|
||||
new(result, delete)
|
||||
result.QObject.setup
|
||||
result.events = events
|
||||
result.threadpool = threadpool
|
||||
result.walletAccountService = walletAccountService
|
||||
result.ethService = ethService
|
||||
result.networkService = networkService
|
||||
result.settingsService = settingsService
|
||||
|
||||
proc init*(self: Service) =
|
||||
discard
|
||||
|
@ -118,4 +141,40 @@ QtObject:
|
|||
limit: limit,
|
||||
loadMore: loadMore
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc estimateGas*(self: Service, from_addr: string, to: string, assetAddress: string, value: string, data: string = ""): string {.slot.} =
|
||||
var response: RpcResponse[JsonNode]
|
||||
try:
|
||||
if assetAddress != ZERO_ADDRESS and not assetAddress.isEmptyOrWhitespace:
|
||||
var tx = buildTokenTransaction(
|
||||
parseAddress(from_addr),
|
||||
parseAddress(assetAddress)
|
||||
)
|
||||
let networkType = self.settingsService.getCurrentNetwork().toNetworkType()
|
||||
let network = self.networkService.getNetwork(networkType)
|
||||
let contract = self.ethService.findErc20Contract(network.chainId, 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")
|
||||
var success: bool
|
||||
let gas = methodThing.estimateGas(tx, transfer, success)
|
||||
|
||||
result = $(%* { "result": gas, "success": success })
|
||||
else:
|
||||
var tx = ens_utils.buildTransaction(
|
||||
parseAddress(from_addr),
|
||||
eth2Wei(parseFloat(value), 18),
|
||||
data = data
|
||||
)
|
||||
tx.to = parseAddress(to).some
|
||||
response = eth.estimateGas(%*[%tx])
|
||||
|
||||
let res = fromHex[int](response.result.getStr)
|
||||
result = $(%* { "result": %res, "success": true })
|
||||
except Exception as e:
|
||||
error "Error estimating gas", msg = e.msg
|
||||
result = $(%* { "result": "-1", "success": false, "error": { "message": e.msg } })
|
||||
|
||||
|
|
|
@ -54,4 +54,17 @@ QtObject {
|
|||
function generateIdenticon(pk) {
|
||||
return globalUtils.generateIdenticon(pk);
|
||||
}
|
||||
|
||||
property string currentCurrency: walletSection.currentCurrency
|
||||
function estimateGas(from_addr, to, assetAddress, value, data) {
|
||||
return walletSectionTransactions.estimateGas(from_addr, to, assetAddress, value, data)
|
||||
}
|
||||
// TODO change this to use a better store once it is moved out of the ENS module
|
||||
property string gasPrice: profileSectionStore.ensUsernamesStore.gasPrice
|
||||
function getFiatValue(balance, cryptoSymbo, fiatSymbol) {
|
||||
return profileSectionStore.ensUsernamesStore.getFiatValue(balance, cryptoSymbo, fiatSymbol)
|
||||
}
|
||||
function getGasEthValue(gweiValue, gasLimit) {
|
||||
return profileSectionStore.ensUsernamesStore.getGasEthValue(gweiValue, gasLimit)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,26 +155,26 @@ ModalPopup {
|
|||
width: stack.width
|
||||
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
||||
// Not Refactored Yet
|
||||
// if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address &&
|
||||
// selectRecipient.selectedRecipient && selectRecipient.selectedRecipient.address &&
|
||||
// txtAmount.selectedAsset && txtAmount.selectedAsset.address &&
|
||||
// txtAmount.selectedAmount)) return
|
||||
if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address &&
|
||||
selectRecipient.selectedRecipient && selectRecipient.selectedRecipient.address &&
|
||||
txtAmount.selectedAsset && txtAmount.selectedAsset.address &&
|
||||
txtAmount.selectedAmount)) return
|
||||
|
||||
// let gasEstimate = JSON.parse(walletModel.gasView.estimateGas(
|
||||
// selectFromAccount.selectedAccount.address,
|
||||
// selectRecipient.selectedRecipient.address,
|
||||
// txtAmount.selectedAsset.address,
|
||||
// txtAmount.selectedAmount,
|
||||
// ""))
|
||||
let gasEstimate = JSON.parse(walletModel.gasView.estimateGas(
|
||||
selectFromAccount.selectedAccount.address,
|
||||
selectRecipient.selectedRecipient.address,
|
||||
txtAmount.selectedAsset.address,
|
||||
txtAmount.selectedAmount,
|
||||
""))
|
||||
|
||||
// if (!gasEstimate.success) {
|
||||
// //% "Error estimating gas: %1"
|
||||
// console.warn(qsTrId("error-estimating-gas---1").arg(gasEstimate.error.message))
|
||||
// return
|
||||
// }
|
||||
if (!gasEstimate.success) {
|
||||
//% "Error estimating gas: %1"
|
||||
console.warn(qsTrId("error-estimating-gas---1").arg(gasEstimate.error.message))
|
||||
return
|
||||
}
|
||||
|
||||
// selectedGasLimit = gasEstimate.result
|
||||
// defaultGasLimit = selectedGasLimit
|
||||
selectedGasLimit = gasEstimate.result
|
||||
defaultGasLimit = selectedGasLimit
|
||||
})
|
||||
}
|
||||
GasValidator {
|
||||
|
@ -256,7 +256,6 @@ ModalPopup {
|
|||
|
||||
StatusButton {
|
||||
id: btnNext
|
||||
anchors.right: parent.right
|
||||
//% "Next"
|
||||
text: qsTrId("next")
|
||||
enabled: stack.currentGroup.isValid && !stack.currentGroup.isPending
|
||||
|
|
|
@ -105,7 +105,7 @@ StatusModal {
|
|||
// //% "Authorize %1 %2"
|
||||
// return qsTrId("authorize--1--2").arg(approveData.amount).arg(approveData.symbol)
|
||||
// }
|
||||
return qsTrId("command-button-send");
|
||||
return qsTr("Send");
|
||||
}
|
||||
//% "Continue"
|
||||
footerText: qsTrId("continue")
|
||||
|
@ -119,7 +119,7 @@ StatusModal {
|
|||
id: selectFromAccount
|
||||
// Not Refactored Yet
|
||||
// accounts: root.store.walletModelInst.accountsView.accounts
|
||||
// currency: root.store.walletModelInst.balanceView.defaultCurrency
|
||||
currency: root.store.currentCurrency
|
||||
width: stack.width
|
||||
selectedAccount: root.selectedAccount
|
||||
//% "Choose account"
|
||||
|
@ -150,37 +150,35 @@ StatusModal {
|
|||
GasSelector {
|
||||
id: gasSelector
|
||||
anchors.topMargin: Style.current.padding
|
||||
// Not Refactored Yet
|
||||
// gasPrice: parseFloat(root.store.walletModelInst.gasView.gasPrice)
|
||||
// getGasEthValue: root.store.walletModelInst.gasView.getGasEthValue
|
||||
// getFiatValue: root.store.walletModelInst.balanceView.getFiatValue
|
||||
// defaultCurrency: root.store.walletModelInst.balanceView.defaultCurrency
|
||||
gasPrice: parseFloat(root.store.gasPrice)
|
||||
getGasEthValue: root.store.getGasEthValue
|
||||
getFiatValue: root.store.getFiatValue
|
||||
defaultCurrency: root.store.currentCurrency
|
||||
width: stack.width
|
||||
|
||||
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
||||
// Not Refactored Yet
|
||||
// if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address &&
|
||||
// selectRecipient.selectedRecipient && selectRecipient.selectedRecipient.address &&
|
||||
// root.selectedAsset && root.selectedAsset.address &&
|
||||
// root.selectedAmount)) {
|
||||
// selectedGasLimit = 250000
|
||||
// defaultGasLimit = selectedGasLimit
|
||||
// return
|
||||
// }
|
||||
if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address &&
|
||||
selectRecipient.selectedRecipient && selectRecipient.selectedRecipient.address &&
|
||||
root.selectedAsset && root.selectedAsset.address &&
|
||||
root.selectedAmount)) {
|
||||
selectedGasLimit = 250000
|
||||
defaultGasLimit = selectedGasLimit
|
||||
return
|
||||
}
|
||||
|
||||
// let gasEstimate = JSON.parse(root.store.walletModelInst.gasView.estimateGas(
|
||||
// selectFromAccount.selectedAccount.address,
|
||||
// selectRecipient.selectedRecipient.address,
|
||||
// root.selectedAsset.address,
|
||||
// root.selectedAmount,
|
||||
// trxData))
|
||||
let gasEstimate = JSON.parse(root.store.estimateGas(
|
||||
selectFromAccount.selectedAccount.address,
|
||||
selectRecipient.selectedRecipient.address,
|
||||
root.selectedAsset.address,
|
||||
root.selectedAmount,
|
||||
trxData))
|
||||
|
||||
// if (!gasEstimate.success) {
|
||||
// let message = qsTrId("error-estimating-gas---1").arg(gasEstimate.error.message)
|
||||
// root.openGasEstimateErrorPopup(message);
|
||||
// }
|
||||
// selectedGasLimit = gasEstimate.result
|
||||
// defaultGasLimit = selectedGasLimit
|
||||
if (!gasEstimate.success) {
|
||||
let message = qsTr("Error estimating gas: %1").arg(gasEstimate.error.message)
|
||||
root.openGasEstimateErrorPopup(message);
|
||||
}
|
||||
selectedGasLimit = gasEstimate.result
|
||||
defaultGasLimit = selectedGasLimit
|
||||
})
|
||||
}
|
||||
GasValidator {
|
||||
|
@ -217,8 +215,7 @@ StatusModal {
|
|||
toAccount: selectRecipient.selectedRecipient
|
||||
asset: root.selectedAsset
|
||||
amount: { "value": root.selectedAmount, "fiatValue": root.selectedFiatAmount }
|
||||
// Not Refactored Yet
|
||||
// currency: root.store.walletModelInst.balanceView.defaultCurrency
|
||||
currency: root.store.currentCurrency
|
||||
isFromEditable: false
|
||||
trxData: root.trxData
|
||||
isGasEditable: true
|
||||
|
|
Loading…
Reference in New Issue