mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-16 16:47:24 +00:00
feat(dApps) implement sign transaction for wallet connect
Uses status-go's endpoints: - `wallet_buildTransactions` to format the transaction - `wallet_signMessage` to sign the transaction - `wallet_buildRawTransaction` to format the final signed transaction Updates #15126
This commit is contained in:
parent
dfe53c4c7c
commit
92d0420449
@ -249,10 +249,12 @@ QtObject:
|
|||||||
|
|
||||||
# setup other event handlers
|
# setup other event handlers
|
||||||
self.eventsHandler.onFilteringDone(proc (jsonObj: JsonNode) =
|
self.eventsHandler.onFilteringDone(proc (jsonObj: JsonNode) =
|
||||||
|
echo "@dd eventsHandler.onFilteringDone: ", $jsonObj
|
||||||
self.processResponse(jsonObj)
|
self.processResponse(jsonObj)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.eventsHandler.onFilteringUpdateDone(proc (jn: JsonNode) =
|
self.eventsHandler.onFilteringUpdateDone(proc (jn: JsonNode) =
|
||||||
|
echo "@dd eventsHandler.onFilteringUpdateDone: ", $jn
|
||||||
if jn.kind != JArray:
|
if jn.kind != JArray:
|
||||||
error "expected an array"
|
error "expected an array"
|
||||||
|
|
||||||
|
@ -55,3 +55,6 @@ QtObject:
|
|||||||
|
|
||||||
proc signTypedDataV4*(self: Controller, address: string, password: string, typedDataJson: string): string {.slot.} =
|
proc signTypedDataV4*(self: Controller, address: string, password: string, typedDataJson: string): string {.slot.} =
|
||||||
return self.service.signTypedDataV4(address, password, typedDataJson)
|
return self.service.signTypedDataV4(address, password, typedDataJson)
|
||||||
|
|
||||||
|
proc signTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} =
|
||||||
|
return self.service.signTransaction(address, chainId, password, txJson)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import NimQml, chronicles, times
|
import NimQml, chronicles, times, json
|
||||||
|
|
||||||
import backend/wallet_connect as status_go
|
import backend/wallet_connect as status_go
|
||||||
|
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/global/global_singleton
|
import app/global/global_singleton
|
||||||
|
|
||||||
@ -92,3 +94,38 @@ QtObject:
|
|||||||
|
|
||||||
proc signTypedDataV4*(self: Service, address: string, password: string, typedDataJson: string): string =
|
proc signTypedDataV4*(self: Service, address: string, password: string, typedDataJson: string): string =
|
||||||
return status_go.signTypedData(address, password, typedDataJson)
|
return status_go.signTypedData(address, password, typedDataJson)
|
||||||
|
|
||||||
|
proc signTransaction*(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 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.buildRawTransaction(txResponse, chainId, $buildTxResponse["txArgs"], signature)
|
||||||
|
if err.len > 0:
|
||||||
|
error "status-go - wallet_buildRawTransaction failed", err=err
|
||||||
|
return ""
|
||||||
|
if txResponse.isNil or txResponse.kind != JsonNodeKind.JObject or not txResponse.hasKey("rawTx"):
|
||||||
|
error "unexpected buildRawTransaction response"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return txResponse["rawTx"].getStr
|
||||||
|
@ -284,16 +284,20 @@ Item {
|
|||||||
|
|
||||||
// hardcoded for https://react-app.walletconnect.com/
|
// hardcoded for https://react-app.walletconnect.com/
|
||||||
function signMessage(topic, id, address, password, message) {
|
function signMessage(topic, id, address, password, message) {
|
||||||
|
console.info(`calling mocked DAppsStore.signMessage(${topic}, ${id}, ${address}, ${password}, ${message})`)
|
||||||
return "0x0b083acc1b3b612dd38e8e725b28ce9b2dd4936b4cf7922da4e4a3c6f44f7f4f6d3050ccb41455a2b85093f1bfadb10fc6a75d83bb590b2eb70e3447653459701c"
|
return "0x0b083acc1b3b612dd38e8e725b28ce9b2dd4936b4cf7922da4e4a3c6f44f7f4f6d3050ccb41455a2b85093f1bfadb10fc6a75d83bb590b2eb70e3447653459701c"
|
||||||
}
|
}
|
||||||
|
|
||||||
// hardcoded for https://react-app.walletconnect.com/
|
// hardcoded for https://react-app.walletconnect.com/
|
||||||
function signTypedDataV4(topic, id, address, password, typedDataJson) {
|
function signTypedDataV4(topic, id, address, password, typedDataJson) {
|
||||||
|
console.info(`calling mocked DAppsStore.signTypedDataV4(${topic}, ${id}, ${address}, ${password}, ${typedDataJson})`)
|
||||||
return "0xf8ceb3468319cc215523b67c24c4504b3addd9bf8de31c278038d7478c9b6de554f7d8a516cd5d6a066b7d48b81f03d9d6bb7d5d754513c08325674ebcc7efbc1b"
|
return "0xf8ceb3468319cc215523b67c24c4504b3addd9bf8de31c278038d7478c9b6de554f7d8a516cd5d6a066b7d48b81f03d9d6bb7d5d754513c08325674ebcc7efbc1b"
|
||||||
}
|
}
|
||||||
|
|
||||||
function signTransaction(topic, id, address, password, tx) {
|
// hardcoded for https://react-app.walletconnect.com/
|
||||||
return "0xf8ceb3468319cc215523b67c24c4504b3addd9bf8de31c278038d7478c9b6de554f7d8a516cd5d6a066b7d48b81f03d9d6bb7d5d754513c08325674ebcc7efbc1b"
|
function signTransaction(topic, id, address, chainId, password, tx) {
|
||||||
|
console.info(`calling mocked DAppsStore.signTransaction(${topic}, ${id}, ${address}, ${chainId}, ${password}, ${tx})`)
|
||||||
|
return "0xf8672a8402fb7acf82520894e2d622c817878da5143bbe06866ca8e35273ba8a80808401546d71a04fc89c2f007c3b27d0fcff07d3e69c29f940967fab4caf525f9af72dadb48befa00c5312a3cb6f50328889ad361a0c88bb9d1b1a4fc510f6783b287930b4e187b5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +149,17 @@ ConnectedDappsButton {
|
|||||||
root.wcService.requestHandler.rejectSessionRequest(request, userRejected)
|
root.wcService.requestHandler.rejectSessionRequest(request, userRejected)
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.wcService.requestHandler
|
||||||
|
|
||||||
|
function onMaxFeesUpdated(maxFees, symbol) {
|
||||||
|
maxFeesText = `${maxFees.toFixed(2)} ${symbol}`
|
||||||
|
}
|
||||||
|
function onEstimatedTimeUpdated(minMinutes, maxMinutes) {
|
||||||
|
estimatedTimeText = qsTr("%1-%2mins").arg(minMinutes).arg(maxMinutes)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@ 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 estimatedTimeUpdated(int minMinutes, int maxMinutes)
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: sdk
|
target: sdk
|
||||||
@ -119,7 +121,9 @@ QObject {
|
|||||||
method,
|
method,
|
||||||
account,
|
account,
|
||||||
network,
|
network,
|
||||||
data
|
data,
|
||||||
|
maxFeesText: "-",
|
||||||
|
estimatedTimeText: "-"
|
||||||
})
|
})
|
||||||
if (obj === null) {
|
if (obj === null) {
|
||||||
console.error("Error creating SessionRequestResolved for event")
|
console.error("Error creating SessionRequestResolved for event")
|
||||||
@ -141,6 +145,12 @@ QObject {
|
|||||||
}
|
}
|
||||||
obj.resolveDappInfoFromSession(session)
|
obj.resolveDappInfoFromSession(session)
|
||||||
root.sessionRequest(obj)
|
root.sessionRequest(obj)
|
||||||
|
// TODO #15192: update maxFees
|
||||||
|
let gasLimit = parseFloat(parseInt(event.params.request.params[0].gasLimit, 16));
|
||||||
|
let gasPrice = parseFloat(parseInt(event.params.request.params[0].gasPrice, 16));
|
||||||
|
root.maxFeesUpdated((gasLimit * gasPrice)/1000000000, "Gwei")
|
||||||
|
// TODO #15192: update estimatedTime
|
||||||
|
root.estimatedTimeUpdated(3, 12)
|
||||||
})
|
})
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
@ -244,9 +254,9 @@ QObject {
|
|||||||
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)
|
||||||
signedMessage = store.signTransaction(request.topic, request.id,
|
signedMessage = store.signTransaction(request.topic, request.id,
|
||||||
request.account.address, password,
|
request.account.address, request.network.chainId, password, txObj)
|
||||||
SessionRequest.methods.signTransaction.getTxFromData(request.data))
|
|
||||||
}
|
}
|
||||||
let isSuccessful = (signedMessage != "")
|
let isSuccessful = (signedMessage != "")
|
||||||
if (isSuccessful) {
|
if (isSuccessful) {
|
||||||
|
@ -30,7 +30,7 @@ QtObject {
|
|||||||
readonly property string requestDisplay: qsTr("sign this transaction")
|
readonly property string requestDisplay: qsTr("sign this transaction")
|
||||||
|
|
||||||
function buildDataObject(tx) { return {tx} }
|
function buildDataObject(tx) { return {tx} }
|
||||||
function getTxFromData(data) { return data.tx }
|
function getTxObjFromData(data) { return data.tx }
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property QtObject sendTransaction: QtObject {
|
readonly property QtObject sendTransaction: QtObject {
|
||||||
|
@ -443,7 +443,7 @@ StatusDialog {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
case SessionRequest.methods.signTransaction.name: {
|
case SessionRequest.methods.signTransaction.name: {
|
||||||
let tx = SessionRequest.methods.signTransaction.getTxFromData(root.payloadData)
|
let tx = SessionRequest.methods.signTransaction.getTxObjFromData(root.payloadData)
|
||||||
payloadToDisplay = JSON.stringify(tx, null, 2)
|
payloadToDisplay = JSON.stringify(tx, null, 2)
|
||||||
userDisplayNaming = SessionRequest.methods.signTransaction.requestDisplay
|
userDisplayNaming = SessionRequest.methods.signTransaction.requestDisplay
|
||||||
break
|
break
|
||||||
|
@ -33,6 +33,27 @@ QObject {
|
|||||||
return controller.signTypedDataV4(address, password, typedDataJson)
|
return controller.signTypedDataV4(address, password, typedDataJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove leading zeros from hex number as expected by status-go
|
||||||
|
function stripLeadingZeros(hexNumber) {
|
||||||
|
let fixed = hexNumber.replace(/^0x0*/, '0x')
|
||||||
|
return fixed == '0x' ? '0x0' : fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the hex encoded signature of the transaction or empty string if error
|
||||||
|
function signTransaction(topic, id, address, chainId, password, txObj) {
|
||||||
|
// Strip leading zeros from numbers as expected by status-go
|
||||||
|
let tx = {
|
||||||
|
data: txObj.data,
|
||||||
|
from: txObj.from,
|
||||||
|
gasLimit: stripLeadingZeros(txObj.gasLimit),
|
||||||
|
gasPrice: stripLeadingZeros(txObj.gasPrice),
|
||||||
|
nonce: stripLeadingZeros(txObj.nonce),
|
||||||
|
to: txObj.to,
|
||||||
|
value: stripLeadingZeros(txObj.value)
|
||||||
|
}
|
||||||
|
return controller.signTransaction(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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user