mirror of
https://github.com/status-im/status-app.git
synced 2026-09-02 10:01:13 +00:00
fixes #935 A bug occurs when someone requests a large amount of funds from you since the gas estimation will fail and there isn't a way of handling errors in the source yet. This PR handles the error appropriatley for both `estimateGas` and `estimateTokenGas` where the response is only converted from hex to int if the RPC call was successful. Otherwise return the error message as the response and let the UI decide how to display it. Currently the error for gas estimation in transaction bubbles is displayed in a popup however, ive come to realize that 2 popups open instead of one. This is a new bug of which I can't pinpoint the root cause at the moment and have opted to file a separate issue for it.
313 lines
12 KiB
QML
313 lines
12 KiB
QML
import QtQuick 2.13
|
|
import QtQuick.Controls 2.13
|
|
import QtQuick.Layouts 1.13
|
|
import QtQuick.Dialogs 1.3
|
|
import "../../../../../imports"
|
|
import "../../../../../shared"
|
|
import "../../../../../shared/status"
|
|
|
|
ModalPopup {
|
|
property var selectedAccount
|
|
property var selectedRecipient
|
|
property var selectedAsset
|
|
property var selectedAmount
|
|
property var selectedFiatAmount
|
|
property bool outgoing: true
|
|
|
|
property string trxData: ""
|
|
|
|
property alias transactionSigner: transactionSigner
|
|
|
|
property var sendTransaction: function(selectedGasLimit, selectedGasPrice, enteredPassword) {
|
|
let responseStr = walletModel.sendTransaction(selectFromAccount.selectedAccount.address,
|
|
selectRecipient.selectedRecipient.address,
|
|
root.selectedAsset.address,
|
|
root.selectedAmount,
|
|
selectedGasLimit,
|
|
selectedGasPrice,
|
|
enteredPassword,
|
|
stack.uuid)
|
|
|
|
root.close()
|
|
}
|
|
|
|
id: root
|
|
|
|
//% "Send"
|
|
title: qsTrId("command-button-send")
|
|
height: 504
|
|
|
|
property MessageDialog sendingError: MessageDialog {
|
|
id: sendingError
|
|
//% "Error sending the transaction"
|
|
title: qsTrId("error-sending-the-transaction")
|
|
icon: StandardIcon.Critical
|
|
standardButtons: StandardButton.Ok
|
|
}
|
|
|
|
onClosed: {
|
|
stack.pop(groupPreview, StackView.Immediate)
|
|
}
|
|
|
|
TransactionStackView {
|
|
id: stack
|
|
anchors.fill: parent
|
|
anchors.leftMargin: Style.current.padding
|
|
anchors.rightMargin: Style.current.padding
|
|
initialItem: groupPreview
|
|
isLastGroup: stack.currentGroup === groupSignTx
|
|
onGroupActivated: {
|
|
root.title = group.headerText
|
|
btnNext.text = group.footerText
|
|
}
|
|
TransactionFormGroup {
|
|
id: groupSelectAcct
|
|
headerText: {
|
|
if(trxData.startsWith("0x095ea7b3")){
|
|
const approveData = JSON.parse(walletModel.decodeTokenApproval(selectedRecipient.address, trxData))
|
|
if(approveData.symbol)
|
|
return qsTr("Authorize %1 %2").arg(approveData.amount).arg(approveData.symbol)
|
|
}
|
|
return qsTrId("command-button-send");
|
|
}
|
|
footerText: qsTr("Continue")
|
|
showNextBtn: false
|
|
onBackClicked: function() {
|
|
if(validate()) {
|
|
stack.pop()
|
|
}
|
|
}
|
|
AccountSelector {
|
|
id: selectFromAccount
|
|
accounts: walletModel.accounts
|
|
currency: walletModel.defaultCurrency
|
|
width: stack.width
|
|
selectedAccount: root.selectedAccount
|
|
//% "Choose account"
|
|
label: qsTrId("choose-account")
|
|
showBalanceForAssetSymbol: root.selectedAsset.symbol
|
|
minRequiredAssetBalance: parseFloat(root.selectedAmount)
|
|
onSelectedAccountChanged: if (isValid) { gasSelector.estimateGas() }
|
|
}
|
|
RecipientSelector {
|
|
id: selectRecipient
|
|
visible: false
|
|
accounts: walletModel.accounts
|
|
contacts: profileModel.contacts.addedContacts
|
|
selectedRecipient: root.selectedRecipient
|
|
readOnly: true
|
|
}
|
|
}
|
|
TransactionFormGroup {
|
|
id: groupSelectGas
|
|
headerText: qsTr("Network fee")
|
|
//% "Preview"
|
|
footerText: qsTrId("preview")
|
|
showNextBtn: false
|
|
onBackClicked: function() {
|
|
stack.pop()
|
|
}
|
|
GasSelector {
|
|
id: gasSelector
|
|
anchors.topMargin: Style.current.bigPadding
|
|
slowestGasPrice: parseFloat(walletModel.safeLowGasPrice)
|
|
fastestGasPrice: parseFloat(walletModel.fastestGasPrice)
|
|
getGasEthValue: walletModel.getGasEthValue
|
|
getFiatValue: walletModel.getFiatValue
|
|
defaultCurrency: walletModel.defaultCurrency
|
|
width: stack.width
|
|
|
|
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
|
|
if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address &&
|
|
selectRecipient.selectedRecipient && selectRecipient.selectedRecipient.address &&
|
|
root.selectedAsset && root.selectedAsset.address &&
|
|
root.selectedAmount)) {
|
|
selectedGasLimit = 250000
|
|
return
|
|
}
|
|
|
|
let gasEstimate = JSON.parse(walletModel.estimateGas(
|
|
selectFromAccount.selectedAccount.address,
|
|
selectRecipient.selectedRecipient.address,
|
|
root.selectedAsset.address,
|
|
root.selectedAmount,
|
|
trxData))
|
|
|
|
if (!gasEstimate.success) {
|
|
//% "Error estimating gas: %1"
|
|
let message = qsTrId("error-estimating-gas---1").arg(gasEstimate.error.message)
|
|
console.warn(message)
|
|
gasEstimateErrorPopup.confirmationText = message + qsTr(". The transaction will probably fail.")
|
|
gasEstimateErrorPopup.open()
|
|
return
|
|
}
|
|
selectedGasLimit = gasEstimate.result
|
|
})
|
|
}
|
|
GasValidator {
|
|
id: gasValidator
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 8
|
|
selectedAccount: selectFromAccount.selectedAccount
|
|
selectedAmount: parseFloat(root.selectedAmount)
|
|
selectedAsset: root.selectedAsset
|
|
selectedGasEthValue: gasSelector.selectedGasEthValue
|
|
}
|
|
}
|
|
|
|
TransactionFormGroup {
|
|
id: groupPreview
|
|
//% "Transaction preview"
|
|
headerText: qsTrId("transaction-preview")
|
|
//% "Sign with password"
|
|
footerText: qsTrId("sign-with-password")
|
|
showBackBtn: false
|
|
onNextClicked: function() {
|
|
stack.push(groupSignTx, StackView.Immediate)
|
|
}
|
|
isValid: groupSelectAcct.isValid && groupSelectGas.isValid && pvwTransaction.isValid
|
|
|
|
TransactionPreview {
|
|
id: pvwTransaction
|
|
width: stack.width
|
|
fromAccount: selectFromAccount.selectedAccount
|
|
gas: {
|
|
"value": gasSelector.selectedGasEthValue,
|
|
"symbol": "ETH",
|
|
"fiatValue": gasSelector.selectedGasFiatValue
|
|
}
|
|
toAccount: selectRecipient.selectedRecipient
|
|
asset: root.selectedAsset
|
|
amount: { "value": root.selectedAmount, "fiatValue": root.selectedFiatAmount }
|
|
currency: walletModel.defaultCurrency
|
|
isFromEditable: false
|
|
trxData: root.trxData
|
|
isGasEditable: true
|
|
fromValid: balanceValidator.isValid
|
|
gasValid: gasValidator.isValid
|
|
onFromClicked: { stack.push(groupSelectAcct, StackView.Immediate) }
|
|
onGasClicked: { stack.push(groupSelectGas, StackView.Immediate) }
|
|
}
|
|
BalanceValidator {
|
|
id: balanceValidator
|
|
anchors.top: pvwTransaction.bottom
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
account: selectFromAccount.selectedAccount
|
|
amount: !!root.selectedAmount ? parseFloat(root.selectedAmount) : 0.0
|
|
asset: root.selectedAsset
|
|
}
|
|
GasValidator {
|
|
id: gasValidator2
|
|
anchors.top: balanceValidator.visible ? balanceValidator.bottom : pvwTransaction.bottom
|
|
anchors.topMargin: balanceValidator.visible ? 5 : 0
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
selectedAccount: selectFromAccount.selectedAccount
|
|
selectedAmount: parseFloat(root.selectedAmount)
|
|
selectedAsset: root.selectedAsset
|
|
selectedGasEthValue: gasSelector.selectedGasEthValue
|
|
}
|
|
}
|
|
TransactionFormGroup {
|
|
id: groupSignTx
|
|
//% "Sign with password"
|
|
headerText: qsTrId("sign-with-password")
|
|
//% "Send %1 %2"
|
|
footerText: qsTrId("send--1--2").arg(root.selectedAmount).arg(!!root.selectedAsset ? root.selectedAsset.symbol : "")
|
|
onBackClicked: function() {
|
|
stack.pop()
|
|
}
|
|
|
|
TransactionSigner {
|
|
id: transactionSigner
|
|
width: stack.width
|
|
signingPhrase: walletModel.signingPhrase
|
|
}
|
|
}
|
|
}
|
|
|
|
footer: Item {
|
|
width: parent.width
|
|
height: btnNext.height
|
|
|
|
StatusRoundButton {
|
|
id: btnBack
|
|
anchors.left: parent.left
|
|
icon.name: "arrow-right"
|
|
icon.width: 20
|
|
icon.height: 16
|
|
rotation: 180
|
|
visible: stack.currentGroup.showBackBtn
|
|
enabled: stack.currentGroup.isValid || stack.isLastGroup
|
|
onClicked: {
|
|
if (typeof stack.currentGroup.onBackClicked === "function") {
|
|
return stack.currentGroup.onBackClicked()
|
|
}
|
|
stack.back()
|
|
}
|
|
}
|
|
StatusButton {
|
|
id: btnNext
|
|
anchors.right: parent.right
|
|
//% "Next"
|
|
text: qsTrId("next")
|
|
enabled: stack.currentGroup.isValid && !stack.currentGroup.isPending
|
|
visible: stack.currentGroup.showNextBtn
|
|
onClicked: {
|
|
const validity = stack.currentGroup.validate()
|
|
if (validity.isValid && !validity.isPending) {
|
|
if (stack.isLastGroup) {
|
|
return root.sendTransaction(gasSelector.selectedGasLimit,
|
|
gasSelector.selectedGasPrice,
|
|
transactionSigner.enteredPassword)
|
|
}
|
|
if (typeof stack.currentGroup.onNextClicked === "function") {
|
|
return stack.currentGroup.onNextClicked()
|
|
}
|
|
stack.next()
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: walletModel
|
|
onTransactionWasSent: {
|
|
try {
|
|
let response = JSON.parse(txResult)
|
|
|
|
if (response.uuid !== stack.uuid) return
|
|
|
|
stack.currentGroup.isPending = false
|
|
|
|
if (!response.success) {
|
|
if (response.result.includes("could not decrypt key with given password")){
|
|
//% "Wrong password"
|
|
transactionSigner.validationError = qsTrId("wrong-password")
|
|
return
|
|
}
|
|
sendingError.text = response.result
|
|
return sendingError.open()
|
|
}
|
|
|
|
//% "Transaction pending..."
|
|
toastMessage.title = qsTrId("ens-transaction-pending")
|
|
toastMessage.source = "../../../../img/loading.svg"
|
|
toastMessage.iconColor = Style.current.primary
|
|
toastMessage.iconRotates = true
|
|
toastMessage.link = `${walletModel.etherscanLink}/${response.result}`
|
|
toastMessage.open()
|
|
root.close()
|
|
} catch (e) {
|
|
console.error('Error parsing the response', e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*##^##
|
|
Designer {
|
|
D{i:0;autoSize:true;height:480;width:640}
|
|
}
|
|
##^##*/
|
|
|