From 0c1156b33c595d0f83ad4d41f419a39f0e08cea4 Mon Sep 17 00:00:00 2001 From: Jonathan Rainville Date: Fri, 2 Oct 2020 13:23:33 -0400 Subject: [PATCH] feat: reuse signtxModal and show success and failure --- src/app/provider/view.nim | 14 +- ui/app/AppLayouts/Browser/BrowserLayout.qml | 79 +++++++- .../Browser/SendTransactionModal.qml | 187 ------------------ .../ChatComponents/SignTransactionModal.qml | 51 ++--- ui/nim-status-client.pro | 1 - 5 files changed, 114 insertions(+), 218 deletions(-) delete mode 100644 ui/app/AppLayouts/Browser/SendTransactionModal.qml diff --git a/src/app/provider/view.nim b/src/app/provider/view.nim index d96edef966..af4cd9e83d 100644 --- a/src/app/provider/view.nim +++ b/src/app/provider/view.nim @@ -122,12 +122,19 @@ QtObject: # TODO make this async let response = status.wallet.sendTransaction(fromAddress, to, value, selectedGasLimit, selectedGasPrice, password, success) debug "Response", response, success + let errorMessage = if not success: + if response == "": + "web3-response-error" + else: + response + else: + "" + return $ %* { "type": ResponseTypes.Web3SendAsyncCallback, "messageId": data.messageId, - # TODO do we get an error code? - "error": (if response == "" or not success: newJString("web3-response-error") else: newJNull()), - "result": response + "error": errorMessage, + "result": if (success): response else: "" } except Exception as e: error "Error sending the transaction", msg = e.msg @@ -135,7 +142,6 @@ QtObject: "type": ResponseTypes.Web3SendAsyncCallback, "messageId": data.messageId, "error": { - # TODO where does the code come from? "code": 4100, "message": e.msg } diff --git a/ui/app/AppLayouts/Browser/BrowserLayout.qml b/ui/app/AppLayouts/Browser/BrowserLayout.qml index 3d6fb0ae2c..ca63f373c7 100644 --- a/ui/app/AppLayouts/Browser/BrowserLayout.qml +++ b/ui/app/AppLayouts/Browser/BrowserLayout.qml @@ -9,6 +9,7 @@ import QtQuick.Controls.Styles 1.0 import QtQuick.Dialogs 1.2 import "../../../shared" 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 // 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 { id: provider @@ -157,7 +165,72 @@ Item { } else if (request.type === Constants.web3SendAsyncReadOnly && request.payload.method === "eth_sendTransaction") { 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(); walletModel.getGasPricePredictions() } else { diff --git a/ui/app/AppLayouts/Browser/SendTransactionModal.qml b/ui/app/AppLayouts/Browser/SendTransactionModal.qml deleted file mode 100644 index 63dd5ccfbe..0000000000 --- a/ui/app/AppLayouts/Browser/SendTransactionModal.qml +++ /dev/null @@ -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(); - } - } - } -} diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml index bd639df46b..8c50f45184 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml @@ -13,6 +13,31 @@ ModalPopup { property var selectedAmount 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 //% "Send" @@ -31,28 +56,6 @@ ModalPopup { 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 { id: stack anchors.fill: parent @@ -206,7 +209,9 @@ ModalPopup { const validity = stack.currentGroup.validate() if (validity.isValid && !validity.isPending) { if (stack.isLastGroup) { - return root.sendTransaction() + return root.sendTransaction(gasSelector.selectedGasLimit, + gasSelector.selectedGasPrice, + transactionSigner.enteredPassword) } stack.next() } diff --git a/ui/nim-status-client.pro b/ui/nim-status-client.pro index 69dc4bdf52..8b7e520197 100644 --- a/ui/nim-status-client.pro +++ b/ui/nim-status-client.pro @@ -121,7 +121,6 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target DISTFILES += \ - app/AppLayouts/Browser/SendTransactionModal.qml \ app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandButton.qml \ app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml \ app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandsPopup.qml \