feat(dapps) implement eth_sendTransaction support for wallet

Add `Fees` section to request modal

Closes: #15126
This commit is contained in:
Stefan 2024-06-23 11:27:29 +03:00 committed by Stefan Dunca
parent e2949ad6e7
commit 97413d99d1
10 changed files with 205 additions and 29 deletions

View File

@ -58,3 +58,6 @@ QtObject:
proc signTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} = proc signTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} =
return self.service.signTransaction(address, chainId, password, txJson) return self.service.signTransaction(address, chainId, password, txJson)
proc sendTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} =
return self.service.sendTransaction(address, chainId, password, txJson)

View File

@ -5,6 +5,7 @@ import backend/wallet
import app_service/service/settings/service as settings_service import app_service/service/settings/service as settings_service
import app_service/common/wallet_constants import app_service/common/wallet_constants
from app_service/service/transaction/dto import PendingTransactionTypeDto
import app/global/global_singleton import app/global/global_singleton
@ -129,3 +130,39 @@ QtObject:
return "" return ""
return txResponse["rawTx"].getStr return txResponse["rawTx"].getStr
proc sendTransaction*(self: Service, address: string, chainId: int, password: string, txJson: string): string =
var buildTxResponse: JsonNode
var err = wallet.buildTransaction(buildTxResponse, chainId, txJson)
if err.len > 0:
error "status-go - wallet_buildTransaction failed", err=err
return ""
if buildTxResponse.isNil or buildTxResponse.kind != JsonNodeKind.JObject or
not buildTxResponse.hasKey("txArgs") or not buildTxResponse.hasKey("messageToSign"):
error "unexpected wallet_buildTransaction response"
return ""
var txToBeSigned = buildTxResponse["messageToSign"].getStr
if txToBeSigned.len != wallet_constants.TX_HASH_LEN_WITH_PREFIX:
error "unexpected tx hash length"
return ""
var signMsgRes: JsonNode
err = wallet.signMessage(signMsgRes,
txToBeSigned,
address,
hashPassword(password))
if err.len > 0:
error "status-go - wallet_signMessage failed", err=err
let signature = singletonInstance.utils.removeHexPrefix(signMsgRes.getStr)
var txResponse: JsonNode
err = wallet.sendTransactionWithSignature(txResponse, chainId,
$PendingTransactionTypeDto.WalletConnectTransfer, $buildTxResponse["txArgs"], signature)
if err.len > 0:
error "status-go - sendTransactionWithSignature failed", err=err
return ""
if txResponse.isNil or txResponse.kind != JsonNodeKind.JString:
error "unexpected sendTransactionWithSignature response"
return ""
return txResponse.getStr

View File

@ -20,6 +20,7 @@ import shared.popups.walletconnect 1.0
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
import AppLayouts.Wallet.panels 1.0 import AppLayouts.Wallet.panels 1.0
import AppLayouts.Wallet.services.dapps.types 1.0
import utils 1.0 import utils 1.0
import shared.stores 1.0 import shared.stores 1.0
@ -53,6 +54,8 @@ Item {
payloadData: d.currentPayload ? d.currentPayload.payloadData : null payloadData: d.currentPayload ? d.currentPayload.payloadData : null
method: d.currentPayload ? d.currentPayload.method : "" method: d.currentPayload ? d.currentPayload.method : ""
maxFeesText: d.currentPayload ? d.currentPayload.maxFeesText : "" maxFeesText: d.currentPayload ? d.currentPayload.maxFeesText : ""
maxFeesEthText: d.currentPayload ? d.currentPayload.maxFeesEthText : ""
enoughFunds: settings.enoughFunds
estimatedTimeText: d.currentPayload ? d.currentPayload.estimatedTimeText : "" estimatedTimeText: d.currentPayload ? d.currentPayload.estimatedTimeText : ""
account: d.selectedAccount account: d.selectedAccount
@ -119,6 +122,13 @@ Item {
d.currentPayload = d.payloadOptions[currentIndex] d.currentPayload = d.payloadOptions[currentIndex]
} }
} }
StatusCheckBox {
id: enoughFundsCheckBox
text: "Enough funds"
checked: settings.enoughFunds
onCheckedChanged: settings.enoughFunds = checked
}
Item { Layout.fillHeight: true } Item { Layout.fillHeight: true }
} }
@ -132,6 +142,7 @@ Item {
property string dappIcon: "https://opensea.io/static/images/logos/opensea-logo.svg" property string dappIcon: "https://opensea.io/static/images/logos/opensea-logo.svg"
property string accountDisplay: "helloworld" property string accountDisplay: "helloworld"
property int payloadMethod: 0 property int payloadMethod: 0
property bool enoughFunds: true
} }
QtObject { QtObject {
@ -152,21 +163,31 @@ Item {
readonly property var payloadOptions: [ readonly property var payloadOptions: [
{ {
payloadData: {"message":"This is a message to sign.\nSigning this will prove ownership of the account."}, payloadData: {"message":"This is a message to sign.\nSigning this will prove ownership of the account."},
method: "personal_sign", method: SessionRequest.methods.personalSign.name,
maxFeesText: "", maxFeesText: "",
maxFeesEthText: "",
estimatedTimeText: "" estimatedTimeText: ""
}, },
{ {
payloadData: {"message": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"}, payloadData: {"message": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"},
method: "eth_signTypedData_v4", method: SessionRequest.methods.signTypedData_v4.name,
maxFeesText: "", maxFeesText: "",
maxFeesEthText: "",
estimatedTimeText: "" estimatedTimeText: ""
}, },
{ {
payloadData: {"tx":{"data":"0x","from":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","gasLimit":"0x5208","gasPrice":"0x048ddbc5","nonce":"0x2a","to":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","value":"0x00"}}, payloadData: {"tx":{"data":"0x","from":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","gasLimit":"0x5208","gasPrice":"0x048ddbc5","nonce":"0x2a","to":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","value":"0x00"}},
method: "eth_signTransaction", method: SessionRequest.methods.signTransaction.name,
maxFeesText: "1.82 EUR", maxFeesText: "1.82 EUR",
maxFeesEthText: "0.0001 ETH",
estimatedTimeText: "3-5 mins" estimatedTimeText: "3-5 mins"
},
{
payloadData: {"tx":{"data":"0x","from":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","gasLimit":"0x5208","gasPrice":"0x048ddbc5","nonce":"0x2a","to":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","value":"0x00"}},
method: SessionRequest.methods.sendTransaction.name,
maxFeesText: "0.92 EUR",
maxFeesEthText: "0.00005 ETH",
estimatedTimeText: "1-2 mins"
} }
] ]
} }

View File

@ -307,6 +307,11 @@ Item {
console.info(`calling mocked DAppsStore.signTransaction(${topic}, ${id}, ${address}, ${chainId}, ${password}, ${tx})`) console.info(`calling mocked DAppsStore.signTransaction(${topic}, ${id}, ${address}, ${chainId}, ${password}, ${tx})`)
return "0xf8672a8402fb7acf82520894e2d622c817878da5143bbe06866ca8e35273ba8a80808401546d71a04fc89c2f007c3b27d0fcff07d3e69c29f940967fab4caf525f9af72dadb48befa00c5312a3cb6f50328889ad361a0c88bb9d1b1a4fc510f6783b287930b4e187b5" return "0xf8672a8402fb7acf82520894e2d622c817878da5143bbe06866ca8e35273ba8a80808401546d71a04fc89c2f007c3b27d0fcff07d3e69c29f940967fab4caf525f9af72dadb48befa00c5312a3cb6f50328889ad361a0c88bb9d1b1a4fc510f6783b287930b4e187b5"
} }
function sendTransaction(topic, id, address, chainId, password, tx) {
console.info(`calling mocked DAppsStore.sendTransaction(${topic}, ${id}, ${address}, ${chainId}, ${password}, ${tx})`)
return "0xf8672a8402fb7acf82520894e2d622c817878da5143bbe068"
}
} }
walletStore: WalletStore { walletStore: WalletStore {

View File

@ -130,6 +130,8 @@ ConnectedDappsButton {
payloadData: request.data payloadData: request.data
method: request.method method: request.method
maxFeesText: request.maxFeesText maxFeesText: request.maxFeesText
maxFeesEthText: request.maxFeesEthText
enoughFunds: request.enoughFunds
estimatedTimeText: request.estimatedTimeText estimatedTimeText: request.estimatedTimeText
visible: true visible: true
@ -153,8 +155,14 @@ ConnectedDappsButton {
Connections { Connections {
target: root.wcService.requestHandler target: root.wcService.requestHandler
function onMaxFeesUpdated(maxFees, symbol) { function onMaxFeesUpdated(maxFees, maxFeesWei, haveEnoughFunds, symbol) {
maxFeesText = `${maxFees.toFixed(2)} ${symbol}` maxFeesText = `${maxFees.toFixed(2)} ${symbol}`
var ethStr = "?"
if (globalUtils) {
ethStr = globalUtils.wei2Eth(maxFeesWei, 9)
}
maxFeesEthText = `${ethStr} ETH`
enoughFunds = haveEnoughFunds
} }
function onEstimatedTimeUpdated(minMinutes, maxMinutes) { function onEstimatedTimeUpdated(minMinutes, maxMinutes) {
estimatedTimeText = qsTr("%1-%2mins").arg(minMinutes).arg(maxMinutes) estimatedTimeText = qsTr("%1-%2mins").arg(minMinutes).arg(maxMinutes)

View File

@ -32,7 +32,7 @@ QObject {
signal sessionRequest(SessionRequestResolved request) signal sessionRequest(SessionRequestResolved request)
signal displayToastMessage(string message, bool error) signal displayToastMessage(string message, bool error)
signal sessionRequestResult(/*model entry of SessionRequestResolved*/ var request, bool isSuccess) signal sessionRequestResult(/*model entry of SessionRequestResolved*/ var request, bool isSuccess)
signal maxFeesUpdated(real maxFees, string symbol) signal maxFeesUpdated(real maxFees, int maxFeesWei, bool haveEnoughFunds, string symbol)
signal estimatedTimeUpdated(int minMinutes, int maxMinutes) signal estimatedTimeUpdated(int minMinutes, int maxMinutes)
Connections { Connections {
@ -134,8 +134,10 @@ QObject {
account, account,
network, network,
data, data,
maxFeesText: "-", maxFeesText: "?",
estimatedTimeText: "-" maxFeesEthText: "?",
enoughFunds: false,
estimatedTimeText: "?"
}) })
if (obj === null) { if (obj === null) {
console.error("Error creating SessionRequestResolved for event") console.error("Error creating SessionRequestResolved for event")
@ -143,9 +145,7 @@ QObject {
} }
// Check later to have a valid request object // Check later to have a valid request object
if (!SessionRequest.getSupportedMethods().includes(method) if (!SessionRequest.getSupportedMethods().includes(method)) {
// TODO #14927: support method eth_sendTransaction
|| method == SessionRequest.methods.sendTransaction.name) {
console.error("Unsupported method", method) console.error("Unsupported method", method)
return null return null
} }
@ -160,9 +160,10 @@ QObject {
// TODO #15192: update maxFees // TODO #15192: update maxFees
let gasLimit = parseFloat(parseInt(event.params.request.params[0].gasLimit, 16)); let gasLimit = parseFloat(parseInt(event.params.request.params[0].gasLimit, 16));
let gasPrice = parseFloat(parseInt(event.params.request.params[0].gasPrice, 16)); let gasPrice = parseFloat(parseInt(event.params.request.params[0].gasPrice, 16));
root.maxFeesUpdated((gasLimit * gasPrice)/1000000000, "Gwei") let maxFees = gasLimit * gasPrice
root.maxFeesUpdated(maxFees/1000000000, maxFees, true, "Gwei")
// TODO #15192: update estimatedTime // TODO #15192: update estimatedTime
root.estimatedTimeUpdated(3, 12) root.estimatedTimeUpdated(1, 12)
}) })
return obj return obj
@ -181,7 +182,8 @@ QObject {
return null return null
} }
address = event.params.request.params[0] address = event.params.request.params[0]
} else if (method === SessionRequest.methods.signTransaction.name) { } else if (method === SessionRequest.methods.signTransaction.name
|| method === SessionRequest.methods.sendTransaction.name) {
if (event.params.request.params.length == 0) { if (event.params.request.params.length == 0) {
return null return null
} }
@ -233,6 +235,12 @@ QObject {
} }
let tx = event.params.request.params[0] let tx = event.params.request.params[0]
return SessionRequest.methods.signTransaction.buildDataObject(tx) return SessionRequest.methods.signTransaction.buildDataObject(tx)
} else if (method === SessionRequest.methods.sendTransaction.name) {
if (event.params.request.params.length == 0) {
return null
}
let tx = event.params.request.params[0]
return SessionRequest.methods.sendTransaction.buildDataObject(tx)
} else { } else {
return null return null
} }
@ -256,26 +264,30 @@ QObject {
} }
if (password !== "") { if (password !== "") {
var signedMessage = "" var actionResult = ""
if (request.method === SessionRequest.methods.personalSign.name) { if (request.method === SessionRequest.methods.personalSign.name) {
// TODO #14756: clarify why prefixing the message fails the test app https://react-app.walletconnect.com/ // TODO #14756: clarify why prefixing the message fails the test app https://react-app.walletconnect.com/
//let finalMessage = "\x19Ethereum Signed Message:\n" + originalMessage.length + originalMessage //let finalMessage = "\x19Ethereum Signed Message:\n" + originalMessage.length + originalMessage
signedMessage = store.signMessage(request.topic, request.id, actionResult = store.signMessage(request.topic, request.id,
request.account.address, password, request.account.address, password,
SessionRequest.methods.personalSign.getMessageFromData(request.data)) SessionRequest.methods.personalSign.getMessageFromData(request.data))
} else if (request.method === SessionRequest.methods.signTypedData_v4.name) { } else if (request.method === SessionRequest.methods.signTypedData_v4.name) {
signedMessage = store.signTypedDataV4(request.topic, request.id, actionResult = store.signTypedDataV4(request.topic, request.id,
request.account.address, password, request.account.address, password,
SessionRequest.methods.signTypedData_v4.getMessageFromData(request.data)) SessionRequest.methods.signTypedData_v4.getMessageFromData(request.data))
} else if (request.method === SessionRequest.methods.signTransaction.name) { } else if (request.method === SessionRequest.methods.signTransaction.name) {
let txObj = SessionRequest.methods.signTransaction.getTxObjFromData(request.data) let txObj = SessionRequest.methods.signTransaction.getTxObjFromData(request.data)
signedMessage = store.signTransaction(request.topic, request.id, actionResult = store.signTransaction(request.topic, request.id,
request.account.address, request.network.chainId, password, txObj)
} else if (request.method === SessionRequest.methods.sendTransaction.name) {
let txObj = SessionRequest.methods.sendTransaction.getTxObjFromData(request.data)
actionResult = store.sendTransaction(request.topic, request.id,
request.account.address, request.network.chainId, password, txObj) request.account.address, request.network.chainId, password, txObj)
} }
let isSuccessful = (signedMessage != "") let isSuccessful = (actionResult != "")
if (isSuccessful) { if (isSuccessful) {
// acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal // acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal
sdk.acceptSessionRequest(request.topic, request.id, signedMessage) sdk.acceptSessionRequest(request.topic, request.id, actionResult)
} else { } else {
root.sessionRequestResult(request, isSuccessful) root.sessionRequestResult(request, isSuccessful)
} }

View File

@ -6,6 +6,8 @@ import utils 1.0
QtObject { QtObject {
/// Supported methods /// Supported methods
/// userString is used in the context `dapp.url #{userString} <accepted/rejected>`
/// requestDisplay is used in the context `dApp wants you to ${requestDisplay} with <Account Name Here>`
property QtObject methods: QtObject { property QtObject methods: QtObject {
readonly property QtObject personalSign: QtObject { readonly property QtObject personalSign: QtObject {
readonly property string name: Constants.personal_sign readonly property string name: Constants.personal_sign
@ -35,8 +37,11 @@ QtObject {
readonly property QtObject sendTransaction: QtObject { readonly property QtObject sendTransaction: QtObject {
readonly property string name: "eth_sendTransaction" readonly property string name: "eth_sendTransaction"
readonly property string userString: qsTr("send transaction") readonly property string userString: qsTr("transaction")
//function buildDataObject(message) { return {/* TODO #15126 */}} readonly property string requestDisplay: qsTr("sign this transaction")
function buildDataObject(tx) { return {tx}}
function getTxObjFromData(data) { return data.tx }
} }
readonly property var all: [personalSign, signTypedData_v4, signTransaction, sendTransaction] readonly property var all: [personalSign, signTypedData_v4, signTransaction, sendTransaction]
} }

View File

@ -29,6 +29,8 @@ QObject {
readonly property alias dappIcon: d.dappIcon readonly property alias dappIcon: d.dappIcon
readonly property string maxFeesText: "" readonly property string maxFeesText: ""
readonly property string maxFeesEthText: ""
readonly property bool enoughFunds: false
readonly property string estimatedTimeText: "" readonly property string estimatedTimeText: ""
function resolveDappInfoFromSession(session) { function resolveDappInfoFromSession(session) {

View File

@ -25,8 +25,10 @@ StatusDialog {
required property url dappIcon required property url dappIcon
required property string method required property string method
required property var payloadData required property var payloadData
required property string maxFeesText property string maxFeesText: ""
required property string estimatedTimeText property string maxFeesEthText: ""
property bool enoughFunds: false
property string estimatedTimeText: ""
required property var account required property var account
property var network: null property var network: null
@ -126,6 +128,13 @@ StatusDialog {
Item {Layout.fillWidth: true } Item {Layout.fillWidth: true }
} }
} }
StatusBaseText {
text: qsTr("Network")
font.pixelSize: 13
color: Theme.palette.directColor1
}
// TODO #14762: implement proper control to display the chain // TODO #14762: implement proper control to display the chain
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
@ -163,6 +172,62 @@ StatusDialog {
Item {Layout.fillWidth: true } Item {Layout.fillWidth: true }
} }
} }
StatusBaseText {
text: qsTr("Fees")
font.pixelSize: 13
color: Theme.palette.directColor1
visible: d.isTransaction()
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 76
visible: root.network !== null && d.isTransaction()
radius: 8
border.width: 1
border.color: Theme.palette.baseColor2
color: "transparent"
RowLayout {
spacing: 12
anchors.fill: parent
anchors.margins: 16
StatusBaseText {
text: qsTr("Max. fees on %1").arg(!!root.network && root.network.chainName)
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
font.pixelSize: 13
color: Theme.palette.baseColor1
}
Item {Layout.fillWidth: true }
ColumnLayout {
StatusBaseText {
text: root.maxFeesText
Layout.alignment: Qt.AlignRight
font.pixelSize: 13
color: root.enoughFunds ? Theme.palette.directColor1 : Theme.palette.dangerColor1
}
StatusBaseText {
text: root.maxFeesEthText
Layout.alignment: Qt.AlignRight
font.pixelSize: 13
color: root.enoughFunds ? Theme.palette.baseColor1 : Theme.palette.dangerColor1
}
}
}
}
} }
} }
} }
@ -248,7 +313,7 @@ StatusDialog {
visible: !!root.maxFeesText visible: !!root.maxFeesText
font.pixelSize: 16 font.pixelSize: 16
font.weight: Font.DemiBold color: root.enoughFunds ? Theme.palette.directColor1 : Theme.palette.dangerColor1
} }
StatusBaseText { StatusBaseText {
text: qsTr("No fees") text: qsTr("No fees")
@ -269,7 +334,6 @@ StatusDialog {
StatusBaseText { StatusBaseText {
text: root.estimatedTimeText text: root.estimatedTimeText
font.pixelSize: 16 font.pixelSize: 16
font.weight: Font.DemiBold
} }
} }
@ -426,6 +490,10 @@ StatusDialog {
property string payloadToDisplay: "" property string payloadToDisplay: ""
property string userDisplayNaming: "" property string userDisplayNaming: ""
function isTransaction() {
return root.method === SessionRequest.methods.signTransaction.name || root.method === SessionRequest.methods.sendTransaction.name
}
function updateDisplay() { function updateDisplay() {
if (!root.payloadData) if (!root.payloadData)
return return
@ -448,6 +516,12 @@ StatusDialog {
userDisplayNaming = SessionRequest.methods.signTransaction.requestDisplay userDisplayNaming = SessionRequest.methods.signTransaction.requestDisplay
break break
} }
case SessionRequest.methods.sendTransaction.name: {
let tx = SessionRequest.methods.sendTransaction.getTxObjFromData(root.payloadData)
payloadToDisplay = JSON.stringify(tx, null, 2)
userDisplayNaming = SessionRequest.methods.sendTransaction.requestDisplay
break
}
} }
} }
} }

View File

@ -39,10 +39,9 @@ QObject {
return fixed == '0x' ? '0x0' : fixed; return fixed == '0x' ? '0x0' : fixed;
} }
// Returns the hex encoded signature of the transaction or empty string if error // Strip leading zeros from numbers as expected by status-go
function signTransaction(topic, id, address, chainId, password, txObj) { function prepareTxForStatusGo(txObj) {
// Strip leading zeros from numbers as expected by status-go return {
let tx = {
data: txObj.data, data: txObj.data,
from: txObj.from, from: txObj.from,
gasLimit: stripLeadingZeros(txObj.gasLimit), gasLimit: stripLeadingZeros(txObj.gasLimit),
@ -51,9 +50,19 @@ QObject {
to: txObj.to, to: txObj.to,
value: stripLeadingZeros(txObj.value) value: stripLeadingZeros(txObj.value)
} }
}
// Returns the hex encoded signature of the transaction or empty string if error
function signTransaction(topic, id, address, chainId, password, txObj) {
let tx = prepareTxForStatusGo(txObj)
return controller.signTransaction(address, chainId, password, JSON.stringify(tx)) return controller.signTransaction(address, chainId, password, JSON.stringify(tx))
} }
// Returns the hash of the transaction or empty string if error
function sendTransaction(topic, id, address, chainId, password, txObj) {
let tx = prepareTxForStatusGo(txObj)
return controller.sendTransaction(address, chainId, password, JSON.stringify(tx))
}
/// \c getDapps triggers an async response to \c dappsListReceived /// \c getDapps triggers an async response to \c dappsListReceived
function getDapps() { function getDapps() {
return controller.getDapps() return controller.getDapps()