fix: keycard signing integration into wallet connect flows

Fixes: #15957
This commit is contained in:
Sale Djenic 2024-08-09 16:00:28 +02:00 committed by saledjenic
parent 03e75e9532
commit 20f30a52fd
11 changed files with 407 additions and 259 deletions

View File

@ -175,7 +175,7 @@ proc newModule*(
result.collectibleDetailsController = collectible_detailsc.newController(int32(backend_collectibles.CollectiblesRequestID.WalletAccount), networkService, events)
result.filter = initFilter(result.controller)
result.walletConnectService = wc_service.newService(result.events, result.threadpool, settingsService, transactionService)
result.walletConnectService = wc_service.newService(result.events, result.threadpool, settingsService, transactionService, keycardService)
result.walletConnectController = wc_controller.newController(result.walletConnectService, walletAccountService)
result.dappsConnectorService = connector_service.newService(result.events)

View File

@ -1,6 +1,8 @@
import NimQml
import chronicles, times, json
import app/global/global_singleton
import app_service/common/utils
import app_service/service/wallet_connect/service as wallet_connect_service
import app_service/service/wallet_account/service as wallet_account_service
@ -9,6 +11,8 @@ import helpers
logScope:
topics = "wallet-connect-controller"
type
SigningCallbackFn* = proc(topic: string, id: string, keyUid: string, address: string, signature: string)
QtObject:
type
@ -27,6 +31,10 @@ QtObject:
result.QObject.setup
## signals emitted by this controller
proc userAuthenticationResult*(self: Controller, topic: string, id: string, error: bool, password: string, pin: string, payload: string) {.signal.}
proc signingResultReceived*(self: Controller, topic: string, id: string, data: string) {.signal.}
proc addWalletConnectSession*(self: Controller, session_json: string): bool {.slot.} =
return self.service.addSession(session_json)
@ -41,7 +49,7 @@ QtObject:
# Emits signal dappsListReceived with the list of dApps
proc getDapps*(self: Controller): bool {.slot.} =
let res = self.service.getDapps()
if res == "":
if res.len == 0:
return false
else:
self.dappsListReceived(res)
@ -61,32 +69,128 @@ QtObject:
self.activeSessionsReceived(resultStr)
return true
proc userAuthenticationResult*(self: Controller, topic: string, id: string, error: bool, password: string, pin: string, payload: string) {.signal.}
# Beware, it will fail if an authentication is already in progress
proc authenticateUser*(self: Controller, topic: string, id: string, address: string, payload: string): bool {.slot.} =
let acc = self.walletAccountService.getAccountByAddress(address)
if acc.keyUid == "":
let keypair = self.walletAccountService.getKeypairByAccountAddress(address)
if keypair.isNil:
return false
return self.service.authenticateUser(acc.keyUid, proc(password: string, pin: string, success: bool) =
self.userAuthenticationResult(topic, id, success, password, pin, payload)
var keyUid = singletonInstance.userProfile.getKeyUid()
if keypair.migratedToKeycard():
keyUid = keypair.keyUid
return self.service.authenticateUser(keyUid, proc(receivedKeyUid: string, password: string, pin: string) =
if receivedKeyUid.len == 0 or receivedKeyUid != keyUid or password.len == 0:
self.userAuthenticationResult(topic, id, false, "", "", "")
return
self.userAuthenticationResult(topic, id, true, password, pin, payload)
)
proc signMessageUnsafe*(self: Controller, address: string, password: string, message: string): string {.slot.} =
return self.service.signMessageUnsafe(address, password, message)
proc signOnKeycard(self: Controller, address: string): bool =
let keypair = self.walletAccountService.getKeypairByAccountAddress(address)
if keypair.isNil:
raise newException(CatchableError, "cannot resolve keypair for address: " & address)
return keypair.migratedToKeycard()
proc signMessage*(self: Controller, address: string, password: string, message: string): string {.slot.} =
return self.service.signMessage(address, password, message)
proc preparePassword(self: Controller, password: string): string =
if singletonInstance.userProfile.getIsKeycardUser():
return password
return hashPassword(password)
proc safeSignTypedData*(self: Controller, address: string, password: string, typedDataJson: string, chainId: int, legacy: bool): string {.slot.} =
return self.service.safeSignTypedData(address, password, typedDataJson, chainId, legacy)
proc signMessageWithCallback(self: Controller, topic: string, id: string, address: string, message: string, password: string,
pin: string, callback: SigningCallbackFn) =
var res = ""
try:
if message.len == 0:
raise newException(CatchableError, "message is empty")
if self.signOnKeycard(address):
let acc = self.walletAccountService.getAccountByAddress(address)
if acc.isNil:
raise newException(CatchableError, "cannot resolve account for address: " & address)
if not self.service.runSigningOnKeycard(
acc.keyUid,
acc.path,
singletonInstance.utils.removeHexPrefix(message),
pin,
proc(keyUid: string, signature: string) =
if keyUid.len == 0 or keyUid != acc.keyUid or signature.len == 0:
raise newException(CatchableError, "keycard signing failed")
callback(topic, id, keyUid, address, signature)
):
raise newException(CatchableError, "runSigningOnKeycard failed")
debug "signMessageWithCallback: signing on keycard started successfully"
return
let finalPassword = self.preparePassword(password)
res = self.service.signMessage(address, finalPassword, message)
except Exception as e:
error "signMessageWithCallback failed: ", msg=e.msg
callback(topic, id, "", address, res)
proc signTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} =
return self.service.signTransaction(address, chainId, password, txJson)
proc signMessage*(self: Controller, topic: string, id: string, address: string, message: string, password: string, pin: string) {.slot.} =
var res = ""
try:
if message.len == 0:
raise newException(CatchableError, "message is empty")
let hashedMessage = self.service.hashMessageEIP191(message)
if hashedMessage.len == 0:
raise newException(CatchableError, "hashMessageEIP191 failed")
self.signMessageWithCallback(topic, id, address, hashedMessage, password, pin,
proc (topic: string, id: string, keyUid: string, address: string, signature: string) =
self.signingResultReceived(topic, id, signature)
)
except Exception as e:
error "signMessage failed: ", msg=e.msg
self.signingResultReceived(topic, id, res)
proc sendTransaction*(self: Controller, address: string, chainId: int, password: string, txJson: string): string {.slot.} =
return self.service.sendTransaction(address, chainId, password, txJson)
proc signMessageUnsafe*(self: Controller, topic: string, id: string, address: string, message: string, password: string, pin: string) {.slot.} =
self.signMessage(topic, id, address, message, password, pin)
proc safeSignTypedData*(self: Controller, topic: string, id: string, address: string, typedDataJson: string, chainId: int, legacy: bool,
password: string, pin: string): string {.slot.} =
var res = ""
try:
var dataToSign = ""
if legacy:
dataToSign = self.service.hashTypedData(typedDataJson)
else:
dataToSign = self.service.hashTypedDataV4(typedDataJson)
if dataToSign.len == 0:
raise newException(CatchableError, "hashTypedData failed")
self.signMessageWithCallback(topic, id, address, dataToSign, password, pin,
proc (topic: string, id: string, keyUid: string, address: string, signature: string) =
self.signingResultReceived(topic, id, signature)
)
except Exception as e:
error "safeSignTypedData failed: ", msg=e.msg
self.signingResultReceived(topic, id, res)
proc signTransaction*(self: Controller, topic: string, id: string, address: string, chainId: int, txJson: string, password: string, pin: string) {.slot.} =
var res = ""
try:
let (txHash, txData) = self.service.buildTransaction(chainId, txJson)
if txHash.len == 0 or txData.isNil:
raise newException(CatchableError, "building transaction failed")
self.signMessageWithCallback(topic, id, address, txHash, password, pin,
proc (topic: string, id: string, keyUid: string, address: string, signature: string) =
let rawTx = self.service.buildRawTransaction(chainId, $txData, signature)
self.signingResultReceived(topic, id, rawTx)
)
except Exception as e:
error "signTransaction failed: ", msg=e.msg
self.signingResultReceived(topic, id, res)
proc sendTransaction*(self: Controller, topic: string, id: string, address: string, chainId: int, txJson: string, password: string, pin: string) {.slot.} =
var res = ""
try:
let (txHash, txData) = self.service.buildTransaction(chainId, txJson)
if txHash.len == 0 or txData.isNil:
raise newException(CatchableError, "building transaction failed")
self.signMessageWithCallback(topic, id, address, txHash, password, pin,
proc (topic: string, id: string, keyUid: string, address: string, signature: string) =
let signedTxHash = self.service.sendTransactionWithSignature(chainId, $txData, signature)
self.signingResultReceived(topic, id, signedTxHash)
)
except Exception as e:
error "sendTransaction failed: ", msg=e.msg
self.signingResultReceived(topic, id, res)
proc getEstimatedTime(self: Controller, chainId: int, maxFeePerGasHex: string): int {.slot.} =
return self.service.getEstimatedTime(chainId, maxFeePerGasHex).int

View File

@ -1,4 +1,4 @@
import NimQml, chronicles, times, json
import NimQml, chronicles, times, json, uuids
import strutils
import backend/wallet_connect as status_go
@ -8,6 +8,7 @@ import app_service/service/settings/service as settings_service
import app_service/common/wallet_constants
from app_service/service/transaction/dto import PendingTransactionTypeDto
import app_service/service/transaction/service as tr
import app_service/service/keycard/service as keycard_service
import app/global/global_singleton
@ -25,7 +26,8 @@ logScope:
const UNIQUE_WALLET_CONNECT_MODULE_IDENTIFIER* = "WalletSection-WCModule"
type
AuthenticationResponseFn* = proc(password: string, pin: string, success: bool)
AuthenticationResponseFn* = proc(keyUid: string, password: string, pin: string)
SignResponseFn* = proc(keyUid: string, signature: string)
QtObject:
type Service* = ref object of QObject
@ -33,8 +35,11 @@ QtObject:
threadpool: ThreadPool
settingsService: settings_service.Service
transactions: tr.Service
keycardService: keycard_service.Service
connectionKeycardResponse: UUID
authenticationCallback: AuthenticationResponseFn
signCallback: SignResponseFn
proc delete*(self: Service) =
self.QObject.delete
@ -44,6 +49,7 @@ QtObject:
threadpool: ThreadPool,
settingsService: settings_service.Service,
transactions: tr.Service,
keycardService: keycard_service.Service,
): Service =
new(result, delete)
result.QObject.setup
@ -52,25 +58,19 @@ QtObject:
result.threadpool = threadpool
result.settingsService = settings_service
result.transactions = transactions
result.keycardService = keycardService
proc init*(self: Service) =
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED) do(e: Args):
let args = SharedKeycarModuleArgs(e)
if args.uniqueIdentifier != UNIQUE_WALLET_CONNECT_MODULE_IDENTIFIER:
return
if self.authenticationCallback == nil:
error "unexpected user authenticated event; no callback set"
return
defer:
self.authenticationCallback = nil
if args.password == "" and args.pin == "":
info "fail to authenticate user"
self.authenticationCallback("", "", false)
return
self.authenticationCallback(args.password, args.pin, true)
self.authenticationCallback(args.keyUid, args.password, args.pin)
proc addSession*(self: Service, session_json: string): bool =
# TODO #14588: call it async
@ -114,105 +114,104 @@ QtObject:
let testChains = self.settingsService.areTestNetworksEnabled()
# TODO #14588: call it async
return status_go.getDapps(validAtEpoch, testChains)
proc getActiveSessions*(self: Service, validAtTimestamp: int64): JsonNode =
# TODO #14588: call it async
return status_go.getActiveSessions(validAtTimestamp)
# Will fail if another authentication is in progress
proc authenticateUser*(self: Service, keyUid: string, callback: AuthenticationResponseFn): bool =
if self.authenticationCallback != nil:
return false
self.authenticationCallback = callback
let data = SharedKeycarModuleAuthenticationArgs(
uniqueIdentifier: UNIQUE_WALLET_CONNECT_MODULE_IDENTIFIER,
keyUid: keyUid)
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER, data)
return true
proc signMessageUnsafe*(self: Service, address: string, password: string, message: string): string =
return status_go.signMessageUnsafe(address, password, message)
proc hashMessageEIP191*(self: Service, message: string): string =
let hashRes = hashMessageEIP191("0x" & toHex(message))
if not hashRes.error.isNil:
error "hashMessageEIP191 failed: ", msg=hashRes.error.message
return ""
return hashRes.result.getStr()
proc signMessage*(self: Service, address: string, password: string, message: string): string =
return status_go.signMessage(address, password, message)
proc signMessage*(self: Service, address: string, hashedPassword: string, hashedMessage: string): string =
var signMsgRes: JsonNode
let err = wallet.signMessage(signMsgRes,
hashedMessage,
address,
hashedPassword)
if err.len > 0:
error "status-go - wallet_signMessage failed", err=err
return signMsgRes.getStr
proc safeSignTypedData*(self: Service, address: string, password: string, typedDataJson: string, chainId: int, legacy: bool): string =
return status_go.safeSignTypedData(address, password, typedDataJson, chainId, legacy)
proc signTransaction*(self: Service, address: string, chainId: int, password: string, txJson: string): string =
proc buildTransaction*(self: Service, chainId: int, txJson: string): tuple[txToSign: string, txData: JsonNode] =
var buildTxResponse: JsonNode
var err = wallet.buildTransaction(buildTxResponse, chainId, txJson)
if err.len > 0:
error "status-go - wallet_buildTransaction failed", err=err
return ""
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:
return
result.txToSign = buildTxResponse["messageToSign"].getStr
if result.txToSign.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)
return
result.txData = buildTxResponse["txArgs"]
proc buildRawTransaction*(self: Service, chainId: int, txData: string, signature: string): string =
var txResponse: JsonNode
err = wallet.buildRawTransaction(txResponse, chainId, $buildTxResponse["txArgs"], signature)
var err = wallet.buildRawTransaction(txResponse, chainId, txData, signature)
if err.len > 0:
error "status-go - wallet_buildRawTransaction failed", err=err
return ""
return
if txResponse.isNil or txResponse.kind != JsonNodeKind.JObject or not txResponse.hasKey("rawTx"):
error "unexpected buildRawTransaction response"
return ""
error "unexpected wallet_buildRawTransaction response"
return
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)
proc sendTransactionWithSignature*(self: Service, chainId: int, txData: string, signature: string): string =
var txResponse: JsonNode
err = wallet.sendTransactionWithSignature(txResponse, chainId,
$PendingTransactionTypeDto.WalletConnectTransfer, $buildTxResponse["txArgs"], signature)
let err = wallet.sendTransactionWithSignature(txResponse,
chainId,
$PendingTransactionTypeDto.WalletConnectTransfer,
txData,
singletonInstance.utils.removeHexPrefix(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
proc hashTypedData*(self: Service, data: string): string =
var response: JsonNode
let err = wallet.hashTypedData(response, data)
if err.len > 0:
error "status-go - hashTypedData failed", err=err
return ""
if response.isNil or response.kind != JsonNodeKind.JString:
error "unexpected hashTypedData response"
return ""
return response.getStr
proc hashTypedDataV4*(self: Service, data: string): string =
var response: JsonNode
let err = wallet.hashTypedDataV4(response, data)
if err.len > 0:
error "status-go - hashTypedDataV4 failed", err=err
return ""
if response.isNil or response.kind != JsonNodeKind.JString:
error "unexpected hashTypedDataV4 response"
return ""
return response.getStr
# empty maxFeePerGasHex will fetch the current chain's maxFeePerGas
proc getEstimatedTime*(self: Service, chainId: int, maxFeePerGasHex: string): EstimatedTime =
var maxFeePerGas: float64
@ -237,4 +236,41 @@ QtObject:
return self.transactions.getEstimatedTime(chainId, $(maxFeePerGas))
proc getSuggestedFees*(self: Service, chainId: int): SuggestedFeesDto =
return self.transactions.suggestedFees(chainId)
return self.transactions.suggestedFees(chainId)
proc disconnectKeycardReponseSignal(self: Service) =
self.events.disconnect(self.connectionKeycardResponse)
proc connectKeycardReponseSignal(self: Service) =
self.connectionKeycardResponse = self.events.onWithUUID(SIGNAL_KEYCARD_RESPONSE) do(e: Args):
let args = KeycardLibArgs(e)
self.disconnectKeycardReponseSignal()
if self.signCallback == nil:
error "unexpected user authenticated event; no callback set"
return
defer:
self.signCallback = nil
let currentFlow = self.keycardService.getCurrentFlow()
if currentFlow != KCSFlowType.Sign:
error "unexpected keycard flow type: ", currentFlow
self.signCallback("", "")
return
let signature = "0x" &
singletonInstance.utils.removeHexPrefix(args.flowEvent.txSignature.r) &
singletonInstance.utils.removeHexPrefix(args.flowEvent.txSignature.s) &
singletonInstance.utils.removeHexPrefix(args.flowEvent.txSignature.v)
self.signCallback(args.flowEvent.keyUid, signature)
proc cancelCurrentFlow*(self: Service) =
self.keycardService.cancelCurrentFlow()
proc runSigningOnKeycard*(self: Service, keyUid: string, path: string, hashedMessageToSign: string, pin: string, callback: SignResponseFn): bool =
if pin.len == 0:
return false
if self.signCallback != nil:
return false
self.signCallback = callback
self.cancelCurrentFlow()
self.connectKeycardReponseSignal()
self.keycardService.startSignFlow(path, hashedMessageToSign, pin)
return true

View File

@ -1,7 +1,9 @@
import json, logging
import json, json_serialization, logging
import core, response_type
from ./gen import rpc
import status_go
rpc(signMessage, "wallet"):
message: string
address: string
@ -92,3 +94,21 @@ proc sendTransactionWithSignature*(resultOut: var JsonNode, chainId: int, txType
except Exception as e:
warn e.msg
return e.msg
proc hashTypedData*(resultOut: var JsonNode, data: string): string =
try:
let rawResponse = status_go.hashTypedData(data)
var response = Json.decode(rawResponse, RpcResponse[JsonNode])
return prepareResponse(resultOut, response)
except Exception as e:
warn e.msg
return e.msg
proc hashTypedDataV4*(resultOut: var JsonNode, data: string): string =
try:
let rawResponse = status_go.hashTypedDataV4(data)
var response = Json.decode(rawResponse, RpcResponse[JsonNode])
return prepareResponse(resultOut, response)
except Exception as e:
warn e.msg
return e.msg

View File

@ -1,15 +1,8 @@
import options, logging
import json, json_serialization
import core, response_type
import strutils
from gen import rpc
import backend/wallet
import status_go
import app_service/service/community/dto/sign_params
import app_service/common/utils
rpc(addWalletConnectSession, "wallet"):
sessionJson: string
@ -23,13 +16,6 @@ rpc(getWalletConnectActiveSessions, "wallet"):
rpc(hashMessageEIP191, "wallet"):
message: string
rpc(safeSignTypedDataForDApps, "wallet"):
typedJson: string
address: string
password: string
chainId: int
legacy: bool
proc isSuccessResponse(rpcResponse: RpcResponse[JsonNode]): bool =
return rpcResponse.error.isNil
@ -53,7 +39,7 @@ proc disconnectSession*(topic: string): bool =
proc getActiveSessions*(validAtTimestamp: int64): JsonNode =
try:
let rpcRes = getWalletConnectActiveSessions(validAtTimestamp)
if(not isSuccessResponse(rpcRes)):
return nil
@ -83,47 +69,4 @@ proc getDapps*(validAtEpoch: int64, testChains: bool): string =
return if jsonArray != "null": jsonArray else: "[]"
except Exception as e:
error "GetWalletConnectDapps failed: ", "msg", e.msg
return ""
proc signMessageUnsafe*(address: string, password: string, message: string): string =
try:
let signParams = SignParamsDto(address: address, password: hashPassword(password), data: "0x" & toHex(message))
let paramsStr = $toJson(signParams)
let rpcResRaw = status_go.signMessage(paramsStr)
let rpcRes = Json.decode(rpcResRaw, RpcResponse[JsonNode])
if(not rpcRes.error.isNil):
return ""
return rpcRes.result.getStr()
except Exception as e:
error "status_go.signMessage failed: ", "msg", e.msg
return ""
proc signMessage*(address: string, password: string, message: string): string =
try:
let hashRes = hashMessageEIP191("0x" & toHex(message))
if not isSuccessResponse(hashRes):
error "wallet_hashMessageEIP191 failed: ", "msg", hashRes.error.message
return ""
let safeHash = hashRes.result.getStr()
let signRes = wallet.signMessage(safeHash, address, hashPassword(password))
if not isSuccessResponse(signRes):
error "wallet_signMessage failed: ", "msg", signRes.error.message
return ""
return signRes.result.getStr()
except Exception as e:
error "signMessageForDApps failed: ", "msg", e.msg
return ""
proc safeSignTypedData*(address: string, password: string, typedDataJson: string, chainId: int, legacy: bool): string =
try:
let rpcRes = safeSignTypedDataForDApps(typedDataJson, address, hashPassword(password), chainId, legacy)
if not isSuccessResponse(rpcRes):
return ""
return rpcRes.result.getStr()
except Exception as e:
error (if legacy: "wallet_safeSignTypedDataForDApps" else: "wallet_signTypedDataV4") & " failed: ", "msg", e.msg
return ""
return ""

View File

@ -274,7 +274,7 @@ Item {
compare(handler.store.authenticateUserCalls.length, 1, "expected a call to store.authenticateUser")
let store = handler.store
store.userAuthenticated(td.topic, td.request.id, "password", "")
store.userAuthenticated(td.topic, td.request.id, "hello world", "")
compare(store.signMessageCalls.length, 1, "expected a call to store.signMessage")
compare(store.signMessageCalls[0].message, td.request.data)
}

View File

@ -116,6 +116,22 @@ SQUtils.QObject {
root.displayToastMessage(qsTr("Failed to authenticate %1 from %2").arg(methodStr).arg(session.peer.metadata.url), true)
})
}
function onSigningResult(topic, id, data) {
let isSuccessful = (data != "")
if (isSuccessful) {
// acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal
sdk.acceptSessionRequest(topic, id, data)
} else {
console.error("signing error")
var request = requests.findRequest(topic, id)
if (request === null) {
console.error("Error finding event for topic", topic, "id", id)
return
}
root.sessionRequestResult(request, isSuccessful)
}
}
}
SQUtils.QObject {
@ -334,64 +350,75 @@ SQUtils.QObject {
return
}
if (password !== "") {
let actionResult = ""
if (request.method === SessionRequest.methods.sign.name) {
actionResult = store.signMessageUnsafe(request.topic, request.id,
request.account.address, password,
SessionRequest.methods.personalSign.getMessageFromData(request.data))
} else if (request.method === SessionRequest.methods.personalSign.name) {
actionResult = store.signMessage(request.topic, request.id,
request.account.address, password,
SessionRequest.methods.personalSign.getMessageFromData(request.data))
} else if (request.method === SessionRequest.methods.signTypedData_v4.name ||
request.method === SessionRequest.methods.signTypedData.name)
{
let legacy = request.method === SessionRequest.methods.signTypedData.name
actionResult = store.safeSignTypedData(request.topic, request.id,
request.account.address, password,
if (password === "") {
console.error("No password provided to sign message")
return
}
if (request.method === SessionRequest.methods.sign.name) {
store.signMessageUnsafe(request.topic,
request.id,
request.account.address,
SessionRequest.methods.personalSign.getMessageFromData(request.data),
password,
pin)
} else if (request.method === SessionRequest.methods.personalSign.name) {
store.signMessage(request.topic,
request.id,
request.account.address,
SessionRequest.methods.personalSign.getMessageFromData(request.data),
password,
pin)
} else if (request.method === SessionRequest.methods.signTypedData_v4.name ||
request.method === SessionRequest.methods.signTypedData.name)
{
let legacy = request.method === SessionRequest.methods.signTypedData.name
store.safeSignTypedData(request.topic,
request.id,
request.account.address,
SessionRequest.methods.signTypedData.getMessageFromData(request.data),
request.network.chainId, legacy)
} else if (d.isTransactionMethod(request.method)) {
let txObj = d.getTxObject(request.method, request.data)
if (!!payload) {
let feesInfoJson = payload
let hexFeesJson = root.store.convertFeesInfoToHex(feesInfoJson)
if (!!hexFeesJson) {
let feesInfo = JSON.parse(hexFeesJson)
if (feesInfo.maxFeePerGas) {
txObj.maxFeePerGas = feesInfo.maxFeePerGas
}
if (feesInfo.maxPriorityFeePerGas) {
txObj.maxPriorityFeePerGas = feesInfo.maxPriorityFeePerGas
}
request.network.chainId,
legacy,
password,
pin)
} else if (d.isTransactionMethod(request.method)) {
let txObj = d.getTxObject(request.method, request.data)
if (!!payload) {
let feesInfoJson = payload
let hexFeesJson = root.store.convertFeesInfoToHex(feesInfoJson)
if (!!hexFeesJson) {
let feesInfo = JSON.parse(hexFeesJson)
if (feesInfo.maxFeePerGas) {
txObj.maxFeePerGas = feesInfo.maxFeePerGas
}
if (feesInfo.maxPriorityFeePerGas) {
txObj.maxPriorityFeePerGas = feesInfo.maxPriorityFeePerGas
}
delete txObj.gasLimit
delete txObj.gasPrice
}
// Remove nonce from txObj to be auto-filled by the wallet
delete txObj.nonce
if (request.method === SessionRequest.methods.signTransaction.name) {
actionResult = store.signTransaction(request.topic, request.id,
request.account.address, request.network.chainId, password, txObj)
} else if (request.method === SessionRequest.methods.sendTransaction.name) {
actionResult = store.sendTransaction(request.topic, request.id,
request.account.address, request.network.chainId, password, txObj)
}
delete txObj.gasLimit
delete txObj.gasPrice
}
// Remove nonce from txObj to be auto-filled by the wallet
delete txObj.nonce
let isSuccessful = (actionResult != "")
if (isSuccessful) {
// acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal
sdk.acceptSessionRequest(request.topic, request.id, actionResult)
} else {
root.sessionRequestResult(request, isSuccessful)
if (request.method === SessionRequest.methods.signTransaction.name) {
store.signTransaction(request.topic,
request.id,
request.account.address,
request.network.chainId,
txObj,
password,
pin)
} else if (request.method === SessionRequest.methods.sendTransaction.name) {
store.sendTransaction(
request.topic,
request.id,
request.account.address,
request.network.chainId,
txObj,
password,
pin)
}
} else if (pin !== "") {
console.debug("TODO #15097 sign message using keycard: ", request.data)
} else {
console.error("No password or pin provided to sign message")
}
}

View File

@ -214,48 +214,59 @@ WalletConnectSDKBase {
return
}
if (password !== "") {
var actionResult = ""
if (request.method === SessionRequest.methods.sign.name) {
actionResult = store.signMessageUnsafe(request.topic, request.id,
request.account.address, password,
SessionRequest.methods.personalSign.getMessageFromData(request.data))
} else if (request.method === SessionRequest.methods.personalSign.name) {
actionResult = store.signMessage(request.topic, request.id,
request.account.address, password,
SessionRequest.methods.personalSign.getMessageFromData(request.data))
} else if (request.method === SessionRequest.methods.signTypedData_v4.name ||
request.method === SessionRequest.methods.signTypedData.name)
{
let legacy = request.method === SessionRequest.methods.signTypedData.name
actionResult = store.safeSignTypedData(request.topic, request.id,
request.account.address, password,
if (password === "") {
console.error("No password provided to sign message")
return
}
if (request.method === SessionRequest.methods.sign.name) {
store.signMessageUnsafe(request.topic,
request.id,
request.account.address,
SessionRequest.methods.personalSign.getMessageFromData(request.data),
password,
pin)
} else if (request.method === SessionRequest.methods.personalSign.name) {
store.signMessage(request.topic,
request.id,
request.account.address,
SessionRequest.methods.personalSign.getMessageFromData(request.data),
password,
pin)
} else if (request.method === SessionRequest.methods.signTypedData_v4.name ||
request.method === SessionRequest.methods.signTypedData.name)
{
let legacy = request.method === SessionRequest.methods.signTypedData.name
store.safeSignTypedData(request.topic,
request.id,
request.account.address,
SessionRequest.methods.signTypedData.getMessageFromData(request.data),
request.network.chainId, legacy)
} else if (request.method === SessionRequest.methods.signTransaction.name) {
let txObj = SessionRequest.methods.signTransaction.getTxObjFromData(request.data)
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)
}
let isSuccessful = (actionResult != "")
if (isSuccessful) {
// acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal
acceptSessionRequest(request.topic, request.method, request.id, actionResult)
} else {
root.sessionRequestResult(request, isSuccessful)
}
} else if (pin !== "") {
console.debug("TODO #15097 sign message using keycard: ", request.data)
} else {
console.error("No password or pin provided to sign message")
request.network.chainId,
legacy,
password,
pin)
} else if (request.method === SessionRequest.methods.signTransaction.name) {
let txObj = SessionRequest.methods.signTransaction.getTxObjFromData(request.data)
store.signTransaction(request.topic,
request.id,
request.account.address,
request.network.chainId,
txObj,
password,
pin)
} else if (request.method === SessionRequest.methods.sendTransaction.name) {
let txObj = SessionRequest.methods.sendTransaction.getTxObjFromData(request.data)
store.sendTransaction(request.topic,
request.id,
request.account.address,
request.network.chainId,
txObj,
password,
pin)
}
}
function acceptSessionRequest(topic, method, id, signature) {
function acceptSessionRequest(topic, id, signature) {
console.debug(`Connector DappsConnectorSDK.acceptSessionRequest; requestId: ${root.requestId}, signature: "${signature}"`)
sessionRequestLoader.active = false
@ -322,6 +333,16 @@ WalletConnectSDKBase {
root.displayToastMessage(qsTr("Failed to authenticate %1").arg(session.peer.metadata.url), true)
})
}
function onSigningResult(topic, id, data) {
let isSuccessful = (data != "")
if (isSuccessful) {
// acceptSessionRequest will trigger an sdk.sessionRequestUserAnswerResult signal
d.acceptSessionRequest(topic, id, data)
} else {
console.error("signing error")
}
}
}
Loader {

View File

@ -245,10 +245,6 @@ QObject {
readonly property var supportedAccountsModel: SortFilterProxyModel {
sourceModel: root.walletRootStore.nonWatchAccounts
filters: ValueFilter {
roleName: "keycardAccount"
value: false
}
}
property var currentSessionProposal: null

View File

@ -12,6 +12,8 @@ QObject {
signal userAuthenticated(string topic, string id, string password, string pin, string payload)
signal userAuthenticationFailed(string topic, string id)
signal signingResult(string topic, string id, string data)
function addWalletConnectSession(sessionJson) {
return controller.addWalletConnectSession(sessionJson)
}
@ -31,19 +33,16 @@ QObject {
}
}
// Returns the hex encoded signature of the message or empty string if error
function signMessageUnsafe(topic, id, address, password, message) {
return controller.signMessageUnsafe(address, password, message)
function signMessageUnsafe(topic, id, address, message, password, pin = "") {
controller.signMessageUnsafe(topic, id, address, message, password, pin)
}
// Returns the hex encoded signature of the message or empty string if error
function signMessage(topic, id, address, password, message) {
return controller.signMessage(address, password, message)
function signMessage(topic, id, address, message, password, pin = "") {
controller.signMessage(topic, id, address, message, password, pin)
}
// Returns the hex encoded signature of the typedDataJson or empty string if error
function safeSignTypedData(topic, id, address, password, typedDataJson, chainId, legacy) {
return controller.safeSignTypedData(address, password, typedDataJson, chainId, legacy)
function safeSignTypedData(topic, id, address, typedDataJson, chainId, legacy, password, pin = "") {
controller.safeSignTypedData(topic, id, address, typedDataJson, chainId, legacy, password, pin)
}
// Remove leading zeros from hex number as expected by status-go
@ -91,16 +90,14 @@ QObject {
return JSON.parse(controller.getSuggestedFeesJson(chainId))
}
// 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))
controller.signTransaction(topic, id, address, chainId, JSON.stringify(tx), password, pin)
}
// Returns the hash of the transaction or empty string if error
function sendTransaction(topic, id, address, chainId, password, txObj) {
function sendTransaction(topic, id, address, chainId, txObj, password, pin = "") {
let tx = prepareTxForStatusGo(txObj)
return controller.sendTransaction(address, chainId, password, JSON.stringify(tx))
controller.sendTransaction(topic, id, address, chainId, JSON.stringify(tx), password, pin)
}
/// \c getDapps triggers an async response to \c dappsListReceived
@ -149,5 +146,9 @@ QObject {
root.userAuthenticationFailed(topic, id)
}
}
function onSigningResultReceived(topic, id, data) {
root.signingResult(topic, id, data)
}
}
}
}

@ -1 +1 @@
Subproject commit 5546ffaea2b2135e7a3da58845e230d8e26fe709
Subproject commit 8923d70ec0348c7b238ce6d5d86ebe6682577ba4