mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-16 08:37:12 +00:00
feat(connector)_: add sign transaction flow (#15662)
fixes #15182 - Implement the sign transaction popup for Accept or Rejecting transactions
This commit is contained in:
parent
9c90f0eab5
commit
347e0df8b0
@ -9,9 +9,26 @@ type ConnectorSendRequestAccountsSignal* = ref object of Signal
|
|||||||
iconUrl*: string
|
iconUrl*: string
|
||||||
requestId*: string
|
requestId*: string
|
||||||
|
|
||||||
|
type ConnectorSendTransactionSignal* = ref object of Signal
|
||||||
|
url*: string
|
||||||
|
name*: string
|
||||||
|
iconUrl*: string
|
||||||
|
requestId*: string
|
||||||
|
chainId*: int
|
||||||
|
txArgs*: string
|
||||||
|
|
||||||
proc fromEvent*(T: type ConnectorSendRequestAccountsSignal, event: JsonNode): ConnectorSendRequestAccountsSignal =
|
proc fromEvent*(T: type ConnectorSendRequestAccountsSignal, event: JsonNode): ConnectorSendRequestAccountsSignal =
|
||||||
result = ConnectorSendRequestAccountsSignal()
|
result = ConnectorSendRequestAccountsSignal()
|
||||||
result.url = event["event"]{"url"}.getStr()
|
result.url = event["event"]{"url"}.getStr()
|
||||||
result.name = event["event"]{"name"}.getStr()
|
result.name = event["event"]{"name"}.getStr()
|
||||||
result.iconUrl = event["event"]{"iconUrl"}.getStr()
|
result.iconUrl = event["event"]{"iconUrl"}.getStr()
|
||||||
result.requestId = event["event"]{"requestId"}.getStr()
|
result.requestId = event["event"]{"requestId"}.getStr()
|
||||||
|
|
||||||
|
proc fromEvent*(T: type ConnectorSendTransactionSignal, event: JsonNode): ConnectorSendTransactionSignal =
|
||||||
|
result = ConnectorSendTransactionSignal()
|
||||||
|
result.url = event["event"]{"url"}.getStr()
|
||||||
|
result.name = event["event"]{"name"}.getStr()
|
||||||
|
result.iconUrl = event["event"]{"iconUrl"}.getStr()
|
||||||
|
result.requestId = event["event"]{"requestId"}.getStr()
|
||||||
|
result.chainId = event["event"]{"chainId"}.getInt()
|
||||||
|
result.txArgs = event["event"]{"txArgs"}.getStr()
|
||||||
|
@ -67,6 +67,7 @@ type SignalType* {.pure.} = enum
|
|||||||
CommunityTokenTransactionStatusChanged = "communityToken.communityTokenTransactionStatusChanged"
|
CommunityTokenTransactionStatusChanged = "communityToken.communityTokenTransactionStatusChanged"
|
||||||
CommunityTokenAction = "communityToken.communityTokenAction"
|
CommunityTokenAction = "communityToken.communityTokenAction"
|
||||||
ConnectorSendRequestAccounts = "connector.sendRequestAccounts"
|
ConnectorSendRequestAccounts = "connector.sendRequestAccounts"
|
||||||
|
ConnectorSendTransaction = "connector.sendTransaction"
|
||||||
Unknown
|
Unknown
|
||||||
|
|
||||||
proc event*(self:SignalType):string =
|
proc event*(self:SignalType):string =
|
||||||
|
@ -136,6 +136,7 @@ QtObject:
|
|||||||
of SignalType.CommunityTokenTransactionStatusChanged: CommunityTokenTransactionStatusChangedSignal.fromEvent(jsonSignal)
|
of SignalType.CommunityTokenTransactionStatusChanged: CommunityTokenTransactionStatusChangedSignal.fromEvent(jsonSignal)
|
||||||
of SignalType.CommunityTokenAction: CommunityTokenActionSignal.fromEvent(jsonSignal)
|
of SignalType.CommunityTokenAction: CommunityTokenActionSignal.fromEvent(jsonSignal)
|
||||||
of SignalType.ConnectorSendRequestAccounts: ConnectorSendRequestAccountsSignal.fromEvent(jsonSignal)
|
of SignalType.ConnectorSendRequestAccounts: ConnectorSendRequestAccountsSignal.fromEvent(jsonSignal)
|
||||||
|
of SignalType.ConnectorSendTransaction: ConnectorSendTransactionSignal.fromEvent(jsonSignal)
|
||||||
else: Signal()
|
else: Signal()
|
||||||
|
|
||||||
result.signalType = signalType
|
result.signalType = signalType
|
||||||
|
@ -7,7 +7,10 @@ import app/core/signals/types
|
|||||||
|
|
||||||
import app_service/service/connector/service as connector_service
|
import app_service/service/connector/service as connector_service
|
||||||
|
|
||||||
|
import app_service/common/utils
|
||||||
|
|
||||||
const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts"
|
const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts"
|
||||||
|
const SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION* = "ConnectorSendTransaction"
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "connector-controller"
|
topics = "connector-controller"
|
||||||
@ -22,6 +25,7 @@ QtObject:
|
|||||||
self.QObject.delete
|
self.QObject.delete
|
||||||
|
|
||||||
proc dappRequestsToConnect*(self: Controller, requestId: string, payload: string) {.signal.}
|
proc dappRequestsToConnect*(self: Controller, requestId: string, payload: string) {.signal.}
|
||||||
|
proc dappValidatesTransaction*(self: Controller, requestId: string, payload: string) {.signal.}
|
||||||
|
|
||||||
proc newController*(service: connector_service.Service, events: EventEmitter): Controller =
|
proc newController*(service: connector_service.Service, events: EventEmitter): Controller =
|
||||||
new(result, delete)
|
new(result, delete)
|
||||||
@ -45,6 +49,18 @@ QtObject:
|
|||||||
|
|
||||||
controller.dappRequestsToConnect(params.requestId, dappInfo.toJson())
|
controller.dappRequestsToConnect(params.requestId, dappInfo.toJson())
|
||||||
|
|
||||||
|
result.events.on(SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION) do(e: Args):
|
||||||
|
let params = ConnectorSendTransactionSignal(e)
|
||||||
|
let dappInfo = %*{
|
||||||
|
"icon": params.iconUrl,
|
||||||
|
"name": params.name,
|
||||||
|
"url": params.url,
|
||||||
|
"chainId": params.chainId,
|
||||||
|
"txArgs": params.txArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
controller.dappValidatesTransaction(params.requestId, dappInfo.toJson())
|
||||||
|
|
||||||
result.QObject.setup
|
result.QObject.setup
|
||||||
|
|
||||||
proc parseSingleUInt(chainIDsString: string): uint =
|
proc parseSingleUInt(chainIDsString: string): uint =
|
||||||
@ -62,4 +78,12 @@ QtObject:
|
|||||||
return self.service.approveDappConnect(requestId, account, chainId)
|
return self.service.approveDappConnect(requestId, account, chainId)
|
||||||
|
|
||||||
proc rejectDappConnectRequest*(self: Controller, requestId: string): bool {.slot.} =
|
proc rejectDappConnectRequest*(self: Controller, requestId: string): bool {.slot.} =
|
||||||
return self.service.rejectDappConnect(requestId)
|
return self.service.rejectDappConnect(requestId)
|
||||||
|
|
||||||
|
proc approveTransactionRequest*(self: Controller, requestId: string, signature: string): bool {.slot.} =
|
||||||
|
let hash = utils.createHash(signature)
|
||||||
|
|
||||||
|
return self.service.approveTransactionRequest(requestId, hash)
|
||||||
|
|
||||||
|
proc rejectTransactionSigning*(self: Controller, requestId: string): bool {.slot.} =
|
||||||
|
return self.service.rejectTransactionSigning(requestId)
|
||||||
|
@ -90,4 +90,9 @@ proc stringToUint256*(value: string): Uint256 =
|
|||||||
parsedValue = value.parse(Uint256)
|
parsedValue = value.parse(Uint256)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
discard
|
discard
|
||||||
return parsedValue
|
return parsedValue
|
||||||
|
|
||||||
|
proc createHash*(signature: string): string =
|
||||||
|
let signatureHex = if signature.startsWith("0x"): signature[2..^1] else: signature
|
||||||
|
|
||||||
|
return hashPassword(signatureHex, true)
|
@ -13,6 +13,7 @@ logScope:
|
|||||||
topics = "connector-service"
|
topics = "connector-service"
|
||||||
|
|
||||||
const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts"
|
const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts"
|
||||||
|
const SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION* = "ConnectorSendTransaction"
|
||||||
|
|
||||||
# Enum with events
|
# Enum with events
|
||||||
type Event* = enum
|
type Event* = enum
|
||||||
@ -52,6 +53,18 @@ QtObject:
|
|||||||
|
|
||||||
self.events.emit(SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS, data)
|
self.events.emit(SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS, data)
|
||||||
)
|
)
|
||||||
|
self.events.on(SignalType.ConnectorSendTransaction.event, proc(e: Args) =
|
||||||
|
if self.eventHandler == nil:
|
||||||
|
return
|
||||||
|
|
||||||
|
var data = ConnectorSendTransactionSignal(e)
|
||||||
|
|
||||||
|
if not data.requestId.len() == 0:
|
||||||
|
error "ConnectorSendTransactionSignal failed, requestId is empty"
|
||||||
|
return
|
||||||
|
|
||||||
|
self.events.emit(SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION, data)
|
||||||
|
)
|
||||||
|
|
||||||
proc registerEventsHandler*(self: Service, handler: EventHandlerFn) =
|
proc registerEventsHandler*(self: Service, handler: EventHandlerFn) =
|
||||||
self.eventHandler = handler
|
self.eventHandler = handler
|
||||||
@ -69,14 +82,33 @@ QtObject:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "requestAccountsAcceptedFinishedRpc failed: ", err=e.msg
|
error "requestAccountsAcceptedFinishedRpc failed: ", err=e.msg
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
proc approveTransactionRequest*(self: Service, requestId: string, hash: string): bool =
|
||||||
|
try:
|
||||||
|
var args = SendTransactionAcceptedArgs()
|
||||||
|
|
||||||
proc rejectDappConnect*(self: Service, requestId: string): bool =
|
args.requestId = requestId
|
||||||
|
args.hash = hash
|
||||||
|
|
||||||
|
return status_go.sendTransactionAcceptedFinishedRpc(args)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error "sendTransactionAcceptedFinishedRpc failed: ", err=e.msg
|
||||||
|
return false
|
||||||
|
|
||||||
|
proc rejectRequest*(self: Service, requestId: string, rpcCall: proc(args: RejectedArgs): bool, message: static[string]): bool =
|
||||||
try:
|
try:
|
||||||
var args = RejectedArgs()
|
var args = RejectedArgs()
|
||||||
args.requestId = requestId
|
args.requestId = requestId
|
||||||
|
|
||||||
return status_go.requestAccountsRejectedFinishedRpc(args)
|
return rpcCall(args)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error "requestAccountsRejectedFinishedRpc failed: ", err=e.msg
|
error message, err=e.msg
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
proc rejectTransactionSigning*(self: Service, requestId: string): bool =
|
||||||
|
rejectRequest(self, requestId, status_go.sendTransactionRejectedFinishedRpc, "sendTransactionRejectedFinishedRpc failed: ")
|
||||||
|
|
||||||
|
proc rejectDappConnect*(self: Service, requestId: string): bool =
|
||||||
|
rejectRequest(self, requestId, status_go.requestAccountsRejectedFinishedRpc, "requestAccountsRejectedFinishedRpc failed: ")
|
||||||
|
@ -6,18 +6,29 @@ from gen import rpc
|
|||||||
|
|
||||||
const
|
const
|
||||||
EventConnectorSendRequestAccounts* = "connector.sendRequestAccounts"
|
EventConnectorSendRequestAccounts* = "connector.sendRequestAccounts"
|
||||||
|
EventConnectorSendTransaction* = "connector.sendTransaction"
|
||||||
|
|
||||||
type RequestAccountsAcceptedArgs* = ref object of RootObj
|
type RequestAccountsAcceptedArgs* = ref object of RootObj
|
||||||
requestId* {.serializedFieldName("requestId").}: string
|
requestId* {.serializedFieldName("requestId").}: string
|
||||||
account* {.serializedFieldName("account").}: string
|
account* {.serializedFieldName("account").}: string
|
||||||
chainId* {.serializedFieldName("chainId").}: uint
|
chainId* {.serializedFieldName("chainId").}: uint
|
||||||
|
|
||||||
|
type SendTransactionAcceptedArgs* = ref object of RootObj
|
||||||
|
requestId* {.serializedFieldName("requestId").}: string
|
||||||
|
hash* {.serializedFieldName("hash").}: string
|
||||||
|
|
||||||
type RejectedArgs* = ref object of RootObj
|
type RejectedArgs* = ref object of RootObj
|
||||||
requestId* {.serializedFieldName("requestId").}: string
|
requestId* {.serializedFieldName("requestId").}: string
|
||||||
|
|
||||||
rpc(requestAccountsAccepted, "connector"):
|
rpc(requestAccountsAccepted, "connector"):
|
||||||
args: RequestAccountsAcceptedArgs
|
args: RequestAccountsAcceptedArgs
|
||||||
|
|
||||||
|
rpc(sendTransactionAccepted, "connector"):
|
||||||
|
args: SendTransactionAcceptedArgs
|
||||||
|
|
||||||
|
rpc(sendTransactionRejected, "connector"):
|
||||||
|
aargs: RejectedArgs
|
||||||
|
|
||||||
rpc(requestAccountsRejected, "connector"):
|
rpc(requestAccountsRejected, "connector"):
|
||||||
args: RejectedArgs
|
args: RejectedArgs
|
||||||
|
|
||||||
@ -28,4 +39,10 @@ proc requestAccountsAcceptedFinishedRpc*(args: RequestAccountsAcceptedArgs): boo
|
|||||||
return isSuccessResponse(requestAccountsAccepted(args))
|
return isSuccessResponse(requestAccountsAccepted(args))
|
||||||
|
|
||||||
proc requestAccountsRejectedFinishedRpc*(args: RejectedArgs): bool =
|
proc requestAccountsRejectedFinishedRpc*(args: RejectedArgs): bool =
|
||||||
return isSuccessResponse(requestAccountsRejected(args))
|
return isSuccessResponse(requestAccountsRejected(args))
|
||||||
|
|
||||||
|
proc sendTransactionAcceptedFinishedRpc*(args: SendTransactionAcceptedArgs): bool =
|
||||||
|
return isSuccessResponse(sendTransactionAccepted(args))
|
||||||
|
|
||||||
|
proc sendTransactionRejectedFinishedRpc*(args: RejectedArgs): bool =
|
||||||
|
return isSuccessResponse(sendTransactionRejected(args))
|
@ -26,19 +26,292 @@ import "types"
|
|||||||
WalletConnectSDKBase {
|
WalletConnectSDKBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
// Nim connector.controller instance
|
|
||||||
property var controller
|
|
||||||
property bool sdkReady: true
|
|
||||||
property bool active: true
|
|
||||||
required property WalletConnectService wcService
|
required property WalletConnectService wcService
|
||||||
required property var walletStore
|
required property var walletStore
|
||||||
|
required property DAppsStore store
|
||||||
|
required property int loginType
|
||||||
|
|
||||||
|
property var controller
|
||||||
|
property var dappInfo: null
|
||||||
|
property var txArgs: null
|
||||||
|
property bool sdkReady: true
|
||||||
|
property bool active: true
|
||||||
property string requestId: ""
|
property string requestId: ""
|
||||||
|
property alias requestsModel: requests
|
||||||
|
|
||||||
projectId: ""
|
projectId: ""
|
||||||
|
|
||||||
implicitWidth: 1
|
implicitWidth: 1
|
||||||
implicitHeight: 1
|
implicitHeight: 1
|
||||||
|
|
||||||
|
// TODO Refactor this code to avoid code duplication from Wallet Connect DAppsRequestHandler
|
||||||
|
// https://github.com/status-im/status-desktop/issues/15711
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
function sessionRequestEvent(event) {
|
||||||
|
let obj = d.resolveAsync(event)
|
||||||
|
if (obj === null) {
|
||||||
|
let error = true
|
||||||
|
controller.rejectTransactionSigning(root.requestId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sessionRequestLoader.request = obj
|
||||||
|
requests.enqueue(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveAsync(event) {
|
||||||
|
let method = event.params.request.method
|
||||||
|
let account = lookupAccountFromEvent(event, method)
|
||||||
|
if(!account) {
|
||||||
|
console.error("Error finding account for event", JSON.stringify(event))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let network = lookupNetworkFromEvent(event, method)
|
||||||
|
if(!network) {
|
||||||
|
console.error("Error finding network for event", JSON.stringify(event))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let data = extractMethodData(event, method)
|
||||||
|
if(!data) {
|
||||||
|
console.error("Error in event data lookup", JSON.stringify(event))
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let enoughFunds = !isTransactionMethod(method)
|
||||||
|
let obj = sessionRequestComponent.createObject(null, {
|
||||||
|
event,
|
||||||
|
topic: event.topic,
|
||||||
|
id: event.id,
|
||||||
|
method,
|
||||||
|
account,
|
||||||
|
network,
|
||||||
|
data,
|
||||||
|
maxFeesText: "?",
|
||||||
|
maxFeesEthText: "?",
|
||||||
|
enoughFunds: enoughFunds,
|
||||||
|
estimatedTimeText: "?"
|
||||||
|
})
|
||||||
|
if (obj === null) {
|
||||||
|
console.error("Error creating SessionRequestResolved for event")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check later to have a valid request object
|
||||||
|
if (!SessionRequest.getSupportedMethods().includes(method)) {
|
||||||
|
console.error("Unsupported method", method)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
let session = getActiveSessions(root.dappInfo)
|
||||||
|
|
||||||
|
if (session === null) {
|
||||||
|
console.error("DAppsRequestHandler.lookupSession: error finding session for topic", obj.topic)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
obj.resolveDappInfoFromSession(session)
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTransactionMethod(method) {
|
||||||
|
return method === SessionRequest.methods.signTransaction.name
|
||||||
|
|| method === SessionRequest.methods.sendTransaction.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns null if the account is not found
|
||||||
|
function lookupAccountFromEvent(event, method) {
|
||||||
|
var address = ""
|
||||||
|
if (method === SessionRequest.methods.personalSign.name) {
|
||||||
|
if (event.params.request.params.length < 2) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
address = event.params.request.params[0]
|
||||||
|
} else if (method === SessionRequest.methods.sign.name) {
|
||||||
|
if (event.params.request.params.length === 1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
address = event.params.request.params[0]
|
||||||
|
} else if(method === SessionRequest.methods.signTypedData_v4.name ||
|
||||||
|
method === SessionRequest.methods.signTypedData.name)
|
||||||
|
{
|
||||||
|
if (event.params.request.params.length < 2) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
address = event.params.request.params[0]
|
||||||
|
} else if (method === SessionRequest.methods.signTransaction.name
|
||||||
|
|| method === SessionRequest.methods.sendTransaction.name) {
|
||||||
|
if (event.params.request.params.length == 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
address = event.params.request.params[0]
|
||||||
|
}
|
||||||
|
return SQUtils.ModelUtils.getFirstModelEntryIf(root.wcService.validAccounts, (account) => {
|
||||||
|
return account.address.toLowerCase() === address.toLowerCase();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns null if the network is not found
|
||||||
|
function lookupNetworkFromEvent(event, method) {
|
||||||
|
if (SessionRequest.getSupportedMethods().includes(method) === false) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let chainId = Helpers.chainIdFromEip155(event.params.chainId)
|
||||||
|
return SQUtils.ModelUtils.getByKey(networksModule.flatNetworks, "chainId", chainId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMethodData(event, method) {
|
||||||
|
if (method === SessionRequest.methods.personalSign.name ||
|
||||||
|
method === SessionRequest.methods.sign.name)
|
||||||
|
{
|
||||||
|
if (event.params.request.params.length < 1) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
var message = ""
|
||||||
|
let messageIndex = (method === SessionRequest.methods.personalSign.name ? 0 : 1)
|
||||||
|
let messageParam = event.params.request.tx.data
|
||||||
|
|
||||||
|
// There is no standard on how data is encoded. Therefore we support hex or utf8
|
||||||
|
if (Helpers.isHex(messageParam)) {
|
||||||
|
message = Helpers.hexToString(messageParam)
|
||||||
|
} else {
|
||||||
|
message = messageParam
|
||||||
|
}
|
||||||
|
return SessionRequest.methods.personalSign.buildDataObject(message)
|
||||||
|
} else if (method === SessionRequest.methods.signTypedData_v4.name ||
|
||||||
|
method === SessionRequest.methods.signTypedData.name)
|
||||||
|
{
|
||||||
|
if (event.params.request.params.length < 2) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let jsonMessage = event.params.request.params[1]
|
||||||
|
let methodObj = method === SessionRequest.methods.signTypedData_v4.name
|
||||||
|
? SessionRequest.methods.signTypedData_v4
|
||||||
|
: SessionRequest.methods.signTypedData
|
||||||
|
return methodObj.buildDataObject(jsonMessage)
|
||||||
|
} else if (method === SessionRequest.methods.signTransaction.name) {
|
||||||
|
if (event.params.request.params.length == 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
let tx = event.params.request.params[0]
|
||||||
|
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 {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeSessionRequest(request, password, pin) {
|
||||||
|
if (!SessionRequest.getSupportedMethods().includes(request.method)) {
|
||||||
|
console.error("Unsupported method to execute: ", request.method)
|
||||||
|
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,
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function acceptSessionRequest(topic, method, id, signature) {
|
||||||
|
console.debug(`WC DappsConnectorSDK.acceptSessionRequest; topic: "${topic}", id: ${root.requestId}, signature: "${signature}"`)
|
||||||
|
|
||||||
|
sessionRequestLoader.active = false
|
||||||
|
controller.approveTransactionRequest(requestId, signature)
|
||||||
|
|
||||||
|
root.wcService.displayToastMessage(qsTr("Successfully signed transaction from %1").arg(root.dappInfo.url), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActiveSessions(dappInfos) {
|
||||||
|
let sessionTemplate = (dappUrl, dappName, dappIcon) => {
|
||||||
|
return {
|
||||||
|
"peer": {
|
||||||
|
"metadata": {
|
||||||
|
"description": "-",
|
||||||
|
"icons": [
|
||||||
|
dappIcon
|
||||||
|
],
|
||||||
|
"name": dappName,
|
||||||
|
"url": dappUrl
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"topic": dappUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionTemplate(dappInfos.url, dappInfos.name, dappInfos.icon)
|
||||||
|
}
|
||||||
|
|
||||||
|
function authenticate(request) {
|
||||||
|
return store.authenticateUser(request.topic, request.id, request.account.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.store
|
||||||
|
|
||||||
|
function onUserAuthenticated(topic, id, password, pin) {
|
||||||
|
var request = requests.findRequest(topic, id)
|
||||||
|
if (request === null) {
|
||||||
|
console.error(">Error finding event for topic", topic, "id", id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.executeSessionRequest(request, password, pin)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onUserAuthenticationFailed(topic, id) {
|
||||||
|
var request = requests.findRequest(topic, id)
|
||||||
|
let methodStr = SessionRequest.methodToUserString(request.method)
|
||||||
|
if (request === null || !methodStr) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.lookupSession(topic, function(session) {
|
||||||
|
if (session === null)
|
||||||
|
return
|
||||||
|
root.displayToastMessage(qsTr("Failed to authenticate %1").arg(session.peer.metadata.url), true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: connectDappLoader
|
id: connectDappLoader
|
||||||
|
|
||||||
@ -59,9 +332,8 @@ WalletConnectSDKBase {
|
|||||||
rejectSession(root.requestId)
|
rejectSession(root.requestId)
|
||||||
connectDappLoader.active = false
|
connectDappLoader.active = false
|
||||||
}
|
}
|
||||||
accounts: root.wcService.validAccounts
|
|
||||||
flatNetworks: root.walletStore.filteredFlatModel
|
flatNetworks: root.walletStore.filteredFlatModel
|
||||||
selectedAccountAddress: root.wcService.selectedAccountAddress
|
accounts: root.wcService.validAccounts
|
||||||
|
|
||||||
dAppUrl: proposalMedatada.url
|
dAppUrl: proposalMedatada.url
|
||||||
dAppName: proposalMedatada.name
|
dAppName: proposalMedatada.name
|
||||||
@ -80,12 +352,141 @@ WalletConnectSDKBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: sessionRequestLoader
|
||||||
|
|
||||||
|
active: false
|
||||||
|
|
||||||
|
onLoaded: item.open()
|
||||||
|
|
||||||
|
property SessionRequestResolved request: null
|
||||||
|
|
||||||
|
property var dappInfo: null
|
||||||
|
|
||||||
|
sourceComponent: DAppSignRequestModal {
|
||||||
|
id: dappRequestModal
|
||||||
|
objectName: "connectorDappsRequestModal"
|
||||||
|
loginType: request.account.migragedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
dappName: request.dappName
|
||||||
|
dappUrl: request.dappUrl
|
||||||
|
dappIcon: request.dappIcon
|
||||||
|
|
||||||
|
accountColor: request.account.color
|
||||||
|
accountName: request.account.name
|
||||||
|
accountAddress: request.account.address
|
||||||
|
accountEmoji: request.account.emoji
|
||||||
|
|
||||||
|
networkName: request.network.chainName
|
||||||
|
networkIconPath: Style.svg(request.network.iconUrl)
|
||||||
|
|
||||||
|
currentCurrency: ""
|
||||||
|
fiatFees: request.maxFeesText
|
||||||
|
cryptoFees: request.maxFeesEthText
|
||||||
|
estimatedTime: ""
|
||||||
|
feesLoading: !request.maxFeesText || !request.maxFeesEthText
|
||||||
|
hasFees: signingTransaction
|
||||||
|
enoughFundsForTransaction: request.enoughFunds
|
||||||
|
enoughFundsForFees: request.enoughFunds
|
||||||
|
|
||||||
|
signingTransaction: request.method === SessionRequest.methods.signTransaction.name || request.method === SessionRequest.methods.sendTransaction.name
|
||||||
|
|
||||||
|
requestPayload: {
|
||||||
|
switch(request.method) {
|
||||||
|
case SessionRequest.methods.personalSign.name:
|
||||||
|
return SessionRequest.methods.personalSign.getMessageFromData(request.data)
|
||||||
|
case SessionRequest.methods.sign.name: {
|
||||||
|
return SessionRequest.methods.sign.getMessageFromData(request.data)
|
||||||
|
}
|
||||||
|
case SessionRequest.methods.signTypedData_v4.name: {
|
||||||
|
const stringPayload = SessionRequest.methods.signTypedData_v4.getMessageFromData(request.data)
|
||||||
|
return JSON.stringify(JSON.parse(stringPayload), null, 2)
|
||||||
|
}
|
||||||
|
case SessionRequest.methods.signTypedData.name: {
|
||||||
|
const stringPayload = SessionRequest.methods.signTypedData.getMessageFromData(root.payloadData)
|
||||||
|
return JSON.stringify(JSON.parse(stringPayload), null, 2)
|
||||||
|
}
|
||||||
|
case SessionRequest.methods.signTransaction.name: {
|
||||||
|
const jsonPayload = SessionRequest.methods.signTransaction.getTxObjFromData(request.data)
|
||||||
|
return JSON.stringify(jsonPayload, null, 2)
|
||||||
|
}
|
||||||
|
case SessionRequest.methods.sendTransaction.name: {
|
||||||
|
const jsonPayload = SessionRequest.methods.sendTransaction.getTxObjFromData(request.data)
|
||||||
|
return JSON.stringify(jsonPayload, null, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: {
|
||||||
|
Qt.callLater( () => {
|
||||||
|
sessionRequestLoader.active = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
if (!request) {
|
||||||
|
console.error("Error signing: request is null")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
d.authenticate(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
onRejected: {
|
||||||
|
sessionRequestLoader.active = false
|
||||||
|
controller.rejectTransactionSigning(root.requestId)
|
||||||
|
root.wcService.displayToastMessage(qsTr("Failed to sign transaction from %1").arg(request.dappUrl), true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: sessionRequestComponent
|
||||||
|
|
||||||
|
SessionRequestResolved {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionRequestsModel {
|
||||||
|
id: requests
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: controller
|
target: controller
|
||||||
|
|
||||||
|
onDappValidatesTransaction: function(requestId, dappInfoString) {
|
||||||
|
var dappInfo = JSON.parse(dappInfoString)
|
||||||
|
root.dappInfo = dappInfo
|
||||||
|
var txArgsParams = JSON.parse(dappInfo.txArgs)
|
||||||
|
root.txArgs = txArgsParams
|
||||||
|
let event = {
|
||||||
|
"id": root.requestId,
|
||||||
|
"topic": dappInfo.url,
|
||||||
|
"params": {
|
||||||
|
"chainId": `eip155:${dappInfo.chainId}`,
|
||||||
|
"request": {
|
||||||
|
"method": SessionRequest.methods.personalSign.name,
|
||||||
|
"tx": {
|
||||||
|
"data": txArgsParams.data,
|
||||||
|
},
|
||||||
|
"params": [
|
||||||
|
txArgsParams.from,
|
||||||
|
txArgsParams.to,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d.sessionRequestEvent(event)
|
||||||
|
|
||||||
|
sessionRequestLoader.active = true
|
||||||
|
root.requestId = requestId
|
||||||
|
}
|
||||||
|
|
||||||
onDappRequestsToConnect: function(requestId, dappInfoString) {
|
onDappRequestsToConnect: function(requestId, dappInfoString) {
|
||||||
var dappInfo = JSON.parse(dappInfoString)
|
var dappInfo = JSON.parse(dappInfoString)
|
||||||
|
root.dappInfo = dappInfo
|
||||||
let sessionProposal = {
|
let sessionProposal = {
|
||||||
"params": {
|
"params": {
|
||||||
"optionalNamespaces": {},
|
"optionalNamespaces": {},
|
||||||
@ -105,7 +506,7 @@ WalletConnectSDKBase {
|
|||||||
`eip155:${dappInfo.chainId}`
|
`eip155:${dappInfo.chainId}`
|
||||||
],
|
],
|
||||||
"events": [],
|
"events": [],
|
||||||
"methods": ["eth_sendTransaction"]
|
"methods": [SessionRequest.methods.personalSign.name]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,10 +520,12 @@ WalletConnectSDKBase {
|
|||||||
|
|
||||||
approveSession: function(requestId, account, selectedChains) {
|
approveSession: function(requestId, account, selectedChains) {
|
||||||
controller.approveDappConnectRequest(requestId, account, JSON.stringify(selectedChains))
|
controller.approveDappConnectRequest(requestId, account, JSON.stringify(selectedChains))
|
||||||
|
root.wcService.displayToastMessage(qsTr("Successfully authenticated %1").arg(root.dappInfo.url), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
rejectSession: function(requestId) {
|
rejectSession: function(requestId) {
|
||||||
controller.rejectDappConnectRequest(requestId)
|
controller.rejectDappConnectRequest(requestId)
|
||||||
|
root.wcService.displayToastMessage(qsTr("Failed to authenticate %1").arg(root.dappInfo.url), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't expect requests for these. They are here only to spot errors
|
// We don't expect requests for these. They are here only to spot errors
|
||||||
|
@ -2054,6 +2054,10 @@ Item {
|
|||||||
controller: WalletStore.RootStore.dappsConnectorController
|
controller: WalletStore.RootStore.dappsConnectorController
|
||||||
wcService: Global.walletConnectService
|
wcService: Global.walletConnectService
|
||||||
walletStore: WalletStore.RootStore
|
walletStore: WalletStore.RootStore
|
||||||
|
store: DAppsStore {
|
||||||
|
controller: WalletStore.RootStore.walletConnectController
|
||||||
|
}
|
||||||
|
loginType: appMain.rootStore.loginType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user