feat: reuse signtxModal and show success and failure

This commit is contained in:
Jonathan Rainville 2020-10-02 13:23:33 -04:00 committed by Iuri Matias
parent 56d6ece3e9
commit 0c1156b33c
5 changed files with 114 additions and 218 deletions

View File

@ -122,12 +122,19 @@ QtObject:
# TODO make this async # TODO make this async
let response = status.wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success) let response = status.wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success)
debug "Response", response, success debug "Response", response, success
let errorMessage = if not success:
if response == "":
"web3-response-error"
else:
response
else:
""
return $ %* { return $ %* {
"type": ResponseTypes.Web3SendAsyncCallback, "type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId, "messageId": data.messageId,
# TODO do we get an error code? "error": errorMessage,
"error": (if response == "" or not success: newJString("web3-response-error") else: newJNull()), "result": if (success): response else: ""
"result": response
} }
except Exception as e: except Exception as e:
error "Error sending the transaction", msg = e.msg error "Error sending the transaction", msg = e.msg
@ -135,7 +142,6 @@ QtObject:
"type": ResponseTypes.Web3SendAsyncCallback, "type": ResponseTypes.Web3SendAsyncCallback,
"messageId": data.messageId, "messageId": data.messageId,
"error": { "error": {
# TODO where does the code come from?
"code": 4100, "code": 4100,
"message": e.msg "message": e.msg
} }

View File

@ -9,6 +9,7 @@ import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import "../../../shared" import "../../../shared"
import "../../../imports" import "../../../imports"
import "../Chat/ChatColumn/ChatComponents"
// Code based on https://code.qt.io/cgit/qt/qtwebengine.git/tree/examples/webengine/quicknanobrowser/BrowserWindow.qml?h=5.15 // Code based on https://code.qt.io/cgit/qt/qtwebengine.git/tree/examples/webengine/quicknanobrowser/BrowserWindow.qml?h=5.15
// Licensed under BSD // Licensed under BSD
@ -121,9 +122,16 @@ Item {
} }
} }
// TODO we'll need a new dialog at one point because this one is not using the same call, but it's good for now
property Component sendTransactionModalComponent: SignTransactionModal {}
property Component sendTransactionModalComponent: SendTransactionModal {} property MessageDialog sendingError: MessageDialog {
id: sendingError
//% "Error sending the transaction"
title: qsTrId("error-sending-the-transaction")
icon: StandardIcon.Critical
standardButtons: StandardButton.Ok
}
QtObject { QtObject {
id: provider id: provider
@ -157,7 +165,72 @@ Item {
} else if (request.type === Constants.web3SendAsyncReadOnly && } else if (request.type === Constants.web3SendAsyncReadOnly &&
request.payload.method === "eth_sendTransaction") { request.payload.method === "eth_sendTransaction") {
const sendDialog = sendTransactionModalComponent.createObject(browserWindow); const sendDialog = sendTransactionModalComponent.createObject(browserWindow);
sendDialog.request = request;
walletModel.setFocusedAccountByAddress(request.payload.params[0].from)
var acc = walletModel.focusedAccount
sendDialog.selectedAccount = {
name: acc.name,
address: request.payload.params[0].from,
iconColor: acc.iconColor,
assets: acc.assets
}
sendDialog.selectedRecipient = {
address: request.payload.params[0].to,
identicon: chatsModel.generateIdenticon(request.payload.params[0].to),
name: chatsModel.activeChannel.name,
type: RecipientSelector.Type.Address
};
// TODO get this from data
sendDialog.selectedAsset = {
name: "ETH",
symbol: "ETH",
address: Constants.zeroAddress
};
const value = utilsModel.wei2Token(request.payload.params[0].value, 18)
sendDialog.selectedAmount = value
// TODO calculate that
sendDialog.selectedFiatAmount = "42";
// TODO change sendTransaction function to the postMessage one
sendDialog.sendTransaction = function (selectedGasLimit, selectedGasPrice, enteredPassword) {
console.log('OK', selectedGasLimit, selectedGasPrice, enteredPassword)
request.payload.selectedGasLimit = selectedGasLimit
request.payload.selectedGasPrice = selectedGasPrice
request.payload.password = enteredPassword
request.payload.params[0].value = value
const response = web3Provider.postMessage(JSON.stringify(request))
provider.web3Response(response)
let responseObj
try {
responseObj = JSON.parse(response)
if (responseObj.error) {
throw new Error(responseObj.error)
}
//% "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}/${responseOnj.result}`
toastMessage.open()
} catch (e) {
if (e.message.includes("could not decrypt key with given password")){
//% "Wrong password"
sendDialog.transactionSigner.validationError = qsTrId("wrong-password")
return
}
sendingError.text = e.message
return sendingError.open()
}
sendDialog.close()
sendDialog.destroy()
}
sendDialog.open(); sendDialog.open();
walletModel.getGasPricePredictions() walletModel.getGasPricePredictions()
} else { } else {

View File

@ -1,187 +0,0 @@
import QtQuick 2.13
import "../../../shared"
import "../../../imports"
ModalPopup {
id: popup
property var request: ({
"type": "web3-send-async-read-only",
"messageId": 13,
"payload": {
"jsonrpc": "2.0",
"id": 19,
"method": "eth_sendTransaction",
"params": [{
"to": "0x2127edab5d08b1e11adf7ae4bae16c2b33fdf74a",
"value": "0x9184e72a000",
"from": "0x2dcb8515ea98701614919cb82d30876780936a76"
}]
},
"hostname": "ciqhsxa6udhk6tho3smjn4kloo5tb2ly4scv5yrbxgsx6wutijucqdq.infura.status.im",
"title": "DAPP"
})
property string fromAccount: request.payload.params[0].from
property string toAccount: request.payload.params[0].to
property string value: {
// TODO get decimals
let val = utilsModel.wei2Token(request.payload.params[0].value, 18)
return val
}
function postMessage(isAllowed) {
request.isAllowed = isAllowed;
provider.web3Response(web3Provider.postMessage(JSON.stringify(request)));
}
onClosed: {
popup.destroy();
}
title: qsTr("Confirm transaction")
height: 600
property string passwordValidationError: ""
property bool loading: false
function validate() {
if (passwordInput.text === "") {
//% "You need to enter a password"
passwordValidationError = qsTrId("you-need-to-enter-a-password")
} else if (passwordInput.text.length < 4) {
//% "Password needs to be 4 characters or more"
passwordValidationError = qsTrId("password-needs-to-be-4-characters-or-more")
} else {
passwordValidationError = ""
}
return passwordValidationError === ""
}
onOpened: {
passwordInput.text = ""
passwordInput.forceActiveFocus(Qt.MouseFocusReason)
}
Column {
spacing: Style.current.smallPadding
width: parent.width
TextWithLabel {
label: qsTr("From")
text: fromAccount
}
TextWithLabel {
label: qsTr("To")
text: toAccount
}
TextWithLabel {
label: qsTr("Value")
text: popup.value
}
Input {
id: passwordInput
//% "Enter your password"
placeholderText: qsTrId("enter-your-password…")
//% "Password"
label: qsTrId("password")
textField.echoMode: TextInput.Password
validationError: popup.passwordValidationError
}
GasSelector {
id: gasSelector
slowestGasPrice: parseFloat(walletModel.safeLowGasPrice)
fastestGasPrice: parseFloat(walletModel.fastestGasPrice)
getGasEthValue: walletModel.getGasEthValue
getFiatValue: walletModel.getFiatValue
defaultCurrency: walletModel.defaultCurrency
width: parent.width
reset: function() {
slowestGasPrice = Qt.binding(function(){ return parseFloat(walletModel.safeLowGasPrice) })
fastestGasPrice = Qt.binding(function(){ return parseFloat(walletModel.fastestGasPrice) })
}
property var estimateGas: Backpressure.debounce(gasSelector, 600, function() {
if (!(fromAccount &&
toAccount &&
// TODO support asset
// txtAmount.selectedAsset && txtAmount.selectedAsset.address &&
popup.value)) return
let gasEstimate = JSON.parse(walletModel.estimateGas(
fromAccount,
toAccount,
// TODO support other assets
Constants.zeroAddress,
popup.value))
if (!gasEstimate.success) {
//% "Error estimating gas: %1"
console.warn(qsTrId("error-estimating-gas---1").arg(gasEstimate.error.message))
return
}
selectedGasLimit = gasEstimate.result
})
}
// TODO find where to get the assets
// GasValidator {
// id: gasValidator
// selectedAccount: request.payload.params[0].from
// selectedAmount: parseFloat(txtAmount.selectedAmount)
// selectedAsset: txtAmount.selectedAsset
// selectedGasEthValue: gasSelector.selectedGasEthValue
// reset: function() {
// selectedAccount = Qt.binding(function() { return selectFromAccount.selectedAccount })
// selectedAmount = Qt.binding(function() { return parseFloat(txtAmount.selectedAmount) })
// selectedAsset = Qt.binding(function() { return txtAmount.selectedAsset })
// selectedGasEthValue = Qt.binding(function() { return gasSelector.selectedGasEthValue })
// }
// }
}
footer: Item {
anchors.fill: parent
StyledButton {
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
label: qsTr("Cancel")
disabled: loading
onClicked: {
// Do we need to send back an error?
popup.close()
}
}
StyledButton {
anchors.top: parent.top
anchors.right: parent.right
anchors.rightMargin: Style.current.padding
label: loading ?
//% "Loading..."
qsTrId("loading") :
qsTr("Confirm")
disabled: loading || passwordInput.text === ""
onClicked : {
loading = true
if (!validate()) {
return loading = false
}
request.payload.selectedGasLimit = gasSelector.selectedGasLimit
request.payload.selectedGasPrice = gasSelector.selectedGasPrice
request.payload.password = passwordInput.text
request.payload.params[0].value = popup.value
provider.web3Response(web3Provider.postMessage(JSON.stringify(request)));
loading = false
popup.close();
}
}
}
}

View File

@ -13,6 +13,31 @@ ModalPopup {
property var selectedAmount property var selectedAmount
property var selectedFiatAmount property var selectedFiatAmount
property alias transactionSigner: transactionSigner
property var sendTransaction: function(selectedGasLimit, selectedGasPrice, enteredPassword) {
let responseStr = walletModel.sendTransaction(root.selectedAccount.address,
root.selectedRecipient.address,
root.selectedAsset.address,
root.selectedAmount,
selectedGasLimit,
selectedGasPrice,
enteredPassword)
let response = JSON.parse(responseStr)
if (response.error) {
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()
}
root.close()
}
id: root id: root
//% "Send" //% "Send"
@ -31,28 +56,6 @@ ModalPopup {
stack.reset() stack.reset()
} }
function sendTransaction() {
let responseStr = walletModel.sendTransaction(root.selectedAccount.address,
root.selectedRecipient.address,
root.selectedAsset.address,
root.selectedAmount,
gasSelector.selectedGasLimit,
gasSelector.selectedGasPrice,
transactionSigner.enteredPassword)
let response = JSON.parse(responseStr)
if (response.error) {
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()
}
root.close()
}
TransactionStackView { TransactionStackView {
id: stack id: stack
anchors.fill: parent anchors.fill: parent
@ -206,7 +209,9 @@ ModalPopup {
const validity = stack.currentGroup.validate() const validity = stack.currentGroup.validate()
if (validity.isValid && !validity.isPending) { if (validity.isValid && !validity.isPending) {
if (stack.isLastGroup) { if (stack.isLastGroup) {
return root.sendTransaction() return root.sendTransaction(gasSelector.selectedGasLimit,
gasSelector.selectedGasPrice,
transactionSigner.enteredPassword)
} }
stack.next() stack.next()
} }

View File

@ -121,7 +121,6 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target !isEmpty(target.path): INSTALLS += target
DISTFILES += \ DISTFILES += \
app/AppLayouts/Browser/SendTransactionModal.qml \
app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandButton.qml \ app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandButton.qml \
app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml \ app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml \
app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandsPopup.qml \ app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandsPopup.qml \