diff --git a/src/app/core/signals/remote_signals/connector.nim b/src/app/core/signals/remote_signals/connector.nim index 4c6537bc7d..1802e9fe73 100644 --- a/src/app/core/signals/remote_signals/connector.nim +++ b/src/app/core/signals/remote_signals/connector.nim @@ -29,6 +29,14 @@ type ConnectorRevokeDAppPermissionSignal* = ref object of Signal name*: string iconUrl*: string +type ConnectorPersonalSignSignal* = ref object of Signal + url*: string + name*: string + iconUrl*: string + requestId*: string + challenge*: string + address*: string + proc fromEvent*(T: type ConnectorSendRequestAccountsSignal, event: JsonNode): ConnectorSendRequestAccountsSignal = result = ConnectorSendRequestAccountsSignal() result.url = event["event"]{"url"}.getStr() @@ -58,3 +66,12 @@ proc fromEvent*(T: type ConnectorRevokeDAppPermissionSignal, event: JsonNode): C result.url = event["event"]{"url"}.getStr() result.name = event["event"]{"name"}.getStr() result.iconUrl = event["event"]{"iconUrl"}.getStr() + +proc fromEvent*(T: type ConnectorPersonalSignSignal, event: JsonNode): ConnectorPersonalSignSignal = + result = ConnectorPersonalSignSignal() + 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.challenge = event["event"]{"challenge"}.getStr() + result.address = event["event"]{"address"}.getStr() \ No newline at end of file diff --git a/src/app/core/signals/remote_signals/signal_type.nim b/src/app/core/signals/remote_signals/signal_type.nim index c6f3b5c876..6ddc0fd0de 100644 --- a/src/app/core/signals/remote_signals/signal_type.nim +++ b/src/app/core/signals/remote_signals/signal_type.nim @@ -74,6 +74,7 @@ type SignalType* {.pure.} = enum ConnectorSendTransaction = "connector.sendTransaction" ConnectorGrantDAppPermission = "connector.dAppPermissionGranted" ConnectorRevokeDAppPermission = "connector.dAppPermissionRevoked" + ConnectorPersonalSign = "connector.personalSign" Unknown proc event*(self:SignalType):string = diff --git a/src/app/core/signals/signals_manager.nim b/src/app/core/signals/signals_manager.nim index 55b1b83bbe..b5ad7a9f70 100644 --- a/src/app/core/signals/signals_manager.nim +++ b/src/app/core/signals/signals_manager.nim @@ -140,10 +140,12 @@ QtObject: of SignalType.LocalPairing: LocalPairingSignal.fromEvent(jsonSignal) of SignalType.CommunityTokenTransactionStatusChanged: CommunityTokenTransactionStatusChangedSignal.fromEvent(jsonSignal) of SignalType.CommunityTokenAction: CommunityTokenActionSignal.fromEvent(jsonSignal) + # connector of SignalType.ConnectorSendRequestAccounts: ConnectorSendRequestAccountsSignal.fromEvent(jsonSignal) of SignalType.ConnectorSendTransaction: ConnectorSendTransactionSignal.fromEvent(jsonSignal) of SignalType.ConnectorGrantDAppPermission: ConnectorGrantDAppPermissionSignal.fromEvent(jsonSignal) of SignalType.ConnectorRevokeDAppPermission: ConnectorRevokeDAppPermissionSignal.fromEvent(jsonSignal) + of SignalType.ConnectorPersonalSign: ConnectorPersonalSignSignal.fromEvent(jsonSignal) else: Signal() result.signalType = signalType diff --git a/src/app/modules/shared_modules/connector/controller.nim b/src/app/modules/shared_modules/connector/controller.nim index 8dd685e0c9..f9dcc68429 100644 --- a/src/app/modules/shared_modules/connector/controller.nim +++ b/src/app/modules/shared_modules/connector/controller.nim @@ -13,6 +13,7 @@ const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts" const SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION* = "ConnectorSendTransaction" const SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION* = "ConnectorGrantDAppPermission" const SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION* = "ConnectorRevokeDAppPermission" +const SIGNAL_CONNECTOR_PERSONAL_SIGN* = "ConnectorPersonalSign" logScope: topics = "connector-controller" @@ -30,12 +31,15 @@ QtObject: proc connected*(self: Controller, payload: string) {.signal.} proc disconnected*(self: Controller, payload: string) {.signal.} - proc signRequested*(self: Controller, requestId: string, payload: string) {.signal.} + proc sendTransaction*(self: Controller, requestId: string, payload: string) {.signal.} + proc personalSign(self: Controller, requestId: string, payload: string) {.signal.} proc approveConnectResponse*(self: Controller, payload: string, error: bool) {.signal.} proc rejectConnectResponse*(self: Controller, payload: string, error: bool) {.signal.} proc approveTransactionResponse*(self: Controller, topic: string, requestId: string, error: bool) {.signal.} proc rejectTransactionResponse*(self: Controller, topic: string, requestId: string, error: bool) {.signal.} + proc approvePersonalSignResponse*(self: Controller, topic: string, requestId: string, error: bool) {.signal.} + proc rejectPersonalSignResponse*(self: Controller, topic: string, requestId: string, error: bool) {.signal.} proc newController*(service: connector_service.Service, events: EventEmitter): Controller = new(result, delete) @@ -69,7 +73,7 @@ QtObject: "txArgs": params.txArgs, } - controller.signRequested(params.requestId, dappInfo.toJson()) + controller.sendTransaction(params.requestId, dappInfo.toJson()) result.events.on(SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION) do(e: Args): let params = ConnectorGrantDAppPermissionSignal(e) @@ -93,6 +97,18 @@ QtObject: controller.disconnected(dappInfo.toJson()) + result.events.on(SIGNAL_CONNECTOR_PERSONAL_SIGN) do(e: Args): + let params = ConnectorPersonalSignSignal(e) + let dappInfo = %*{ + "icon": params.iconUrl, + "name": params.name, + "url": params.url, + "challenge": params.challenge, + "address": params.address, + } + + controller.personalSign(params.requestId, dappInfo.toJson()) + result.QObject.setup proc parseSingleUInt(chainIDsString: string): uint = @@ -129,3 +145,12 @@ QtObject: proc getDApps*(self: Controller): string {.slot.} = return self.service.getDApps() + + proc approvePersonalSigning*(self: Controller, sessionTopic: string, requestId: string, signature: string): bool {.slot.} = + result = self.service.approvePersonalSignRequest(requestId, signature) + self.approvePersonalSignResponse(sessionTopic, requestId, not result) + + + proc rejectPersonalSigning*(self: Controller, sessionTopic: string, requestId: string): bool {.slot.} = + result = self.service.rejectPersonalSigning(requestId) + self.rejectPersonalSignResponse(sessionTopic, requestId, not result) \ No newline at end of file diff --git a/src/app_service/service/connector/service.nim b/src/app_service/service/connector/service.nim index 8af030246b..d617e30d89 100644 --- a/src/app_service/service/connector/service.nim +++ b/src/app_service/service/connector/service.nim @@ -16,6 +16,7 @@ const SIGNAL_CONNECTOR_SEND_REQUEST_ACCOUNTS* = "ConnectorSendRequestAccounts" const SIGNAL_CONNECTOR_EVENT_CONNECTOR_SEND_TRANSACTION* = "ConnectorSendTransaction" const SIGNAL_CONNECTOR_GRANT_DAPP_PERMISSION* = "ConnectorGrantDAppPermission" const SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION* = "ConnectorRevokeDAppPermission" +const SIGNAL_CONNECTOR_EVENT_CONNECTOR_PERSONAL_SIGN* = "ConnectorPersonalSign" # Enum with events type Event* = enum @@ -83,6 +84,18 @@ QtObject: self.events.emit(SIGNAL_CONNECTOR_REVOKE_DAPP_PERMISSION, data) ) + self.events.on(SignalType.ConnectorPersonalSign.event, proc(e: Args) = + if self.eventHandler == nil: + return + + var data = ConnectorPersonalSignSignal(e) + + if not data.requestId.len() == 0: + error "ConnectorPersonalSignSignal failed, requestId is empty" + return + + self.events.emit(SIGNAL_CONNECTOR_EVENT_CONNECTOR_PERSONAL_SIGN, data) + ) proc registerEventsHandler*(self: Service, handler: EventHandlerFn) = self.eventHandler = handler @@ -150,4 +163,19 @@ QtObject: return if jsonArray != "null": jsonArray else: "[]" except Exception as e: error "getDApps failed: ", err=e.msg - return "[]" \ No newline at end of file + return "[]" + + proc approvePersonalSignRequest*(self: Service, requestId: string, signature: string): bool = + try: + var args = PersonalSignAcceptedArgs() + args.requestId = requestId + args.signature = signature + + return status_go.sendPersonalSignAcceptedFinishedRpc(args) + + except Exception as e: + error "sendPersonalSigAcceptedFinishedRpc failed: ", err=e.msg + return false + + proc rejectPersonalSigning*(self: Service, requestId: string): bool = + rejectRequest(self, requestId, status_go.sendPersonalSignRejectedFinishedRpc, "sendPersonalSignRejectedFinishedRpc failed: ") \ No newline at end of file diff --git a/src/backend/connector.nim b/src/backend/connector.nim index 183ae4754c..4f084aa24f 100644 --- a/src/backend/connector.nim +++ b/src/backend/connector.nim @@ -23,6 +23,10 @@ type RejectedArgs* = ref object of RootObj type RecallDAppPermissionArgs* = ref object of RootObj dAppUrl* {.serializedFieldName("dAppUrl").}: string +type PersonalSignAcceptedArgs* = ref object of RootObj + requestId* {.serializedFieldName("requestId").}: string + signature* {.serializedFieldName("signature").}: string + rpc(requestAccountsAccepted, "connector"): args: RequestAccountsAcceptedArgs @@ -41,6 +45,12 @@ rpc(recallDAppPermission, "connector"): rpc(getPermittedDAppsList, "connector"): discard +rpc(personalSignAccepted, "connector"): + args: PersonalSignAcceptedArgs + +rpc(personalSignRejected, "connector"): + args: RejectedArgs + proc isSuccessResponse(rpcResponse: RpcResponse[JsonNode]): bool = return rpcResponse.error.isNil @@ -57,4 +67,10 @@ proc sendTransactionRejectedFinishedRpc*(args: RejectedArgs): bool = return isSuccessResponse(sendTransactionRejected(args)) proc recallDAppPermissionFinishedRpc*(dAppUrl: string): bool = - return isSuccessResponse(recallDAppPermission(dAppUrl)) \ No newline at end of file + return isSuccessResponse(recallDAppPermission(dAppUrl)) + +proc sendPersonalSignAcceptedFinishedRpc*(args: PersonalSignAcceptedArgs): bool = + return isSuccessResponse(personalSignAccepted(args)) + +proc sendPersonalSignRejectedFinishedRpc*(args: RejectedArgs): bool = + return isSuccessResponse(personalSignRejected(args)) \ No newline at end of file diff --git a/ui/app/AppLayouts/Wallet/services/dapps/DappsConnectorSDK.qml b/ui/app/AppLayouts/Wallet/services/dapps/DappsConnectorSDK.qml index f4e5290bdd..16ea4f89aa 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/DappsConnectorSDK.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/DappsConnectorSDK.qml @@ -38,14 +38,37 @@ WalletConnectSDKBase { target: root.store enabled: root.enabled - function onSignRequested(requestId, dappInfoString) { + function onSendTransaction(requestId, dappInfoString) { try { var dappInfo = JSON.parse(dappInfoString) var txArgsParams = JSON.parse(dappInfo.txArgs) - let event = d.buildSessionRequest(requestId, dappInfo.url, dappInfo.chainId, SessionRequest.methods.sendTransaction.name, txArgsParams) + let event = d.buildTransactionRequest(requestId, dappInfo.url, dappInfo.chainId, txArgsParams) + d.sessionRequests.set(requestId, event) root.sessionRequestEvent(event) } catch (e) { + d.sessionRequests.delete(requestId) + root.store.rejectTransaction("", requestId, "Failed to parse dappInfo for session request") + console.error("Failed to parse dappInfo for session request", e) + } + } + + function onPersonalSign(requestId, dappInfoString) { + try { + const dappInfo = JSON.parse(dappInfoString) + const mainNet = SQUtils.ModelUtils.getByKey(root.networksModel, "layer", 1) + if (!mainNet) { + root.store.rejectPersonalSign(requestId) + console.error("Mainnet not found - personal sign failed") + return + } + + const event = d.buildSignRequest(requestId, dappInfo.url, mainNet.chainId, dappInfo.challenge, dappInfo.address) + d.sessionRequests.set(requestId, event) + root.sessionRequestEvent(event) + } catch (e) { + d.sessionRequests.delete(requestId) + root.store.rejectPersonalSign("", requestId) console.error("Failed to parse dappInfo for session request", e) } } @@ -87,6 +110,24 @@ WalletConnectSDKBase { console.error("Failed to reject transaction response", e) } } + + function onApprovePersonalSignResponse(topic, requestId, error) { + try { + const errorStr = error ? "Faled to approve personal sign" : "" + root.sessionRequestUserAnswerResult(topic, requestId, true, errorStr) + } catch (e) { + console.error("Failed to approve personal sign response", e) + } + } + + function onRejectPersonalSignResponse(topic, requestId, error) { + try { + const errorStr = error ? "Faled to reject personal sign" : "" + root.sessionRequestUserAnswerResult(topic, requestId, false, errorStr) + } catch (e) { + console.error("Failed to reject personal sign response", e) + } + } } approveSession: function(requestId, account, selectedChains) { @@ -116,11 +157,37 @@ WalletConnectSDKBase { } acceptSessionRequest: function(topic, requestId, signature) { - root.store.approveTransaction(topic, requestId, signature) + if (!d.sessionRequests.has(requestId)) { + root.sessionRequestUserAnswerResult(topic, requestId, false, "Unknown request method") + console.error("Session request not found") + return + } + const event = d.sessionRequests.get(requestId) + if (event.params.request.method === SessionRequest.methods.sendTransaction.name) { + root.store.approveTransaction(topic, requestId, signature) + } else if (event.params.request.method === SessionRequest.methods.personalSign.name) { + root.store.approvePersonalSign(topic, requestId, signature) + } else { + root.sessionRequestUserAnswerResult(topic, requestId, false, "Unknown request method") + console.error("Unknown request method", event.params.request.method) + } } rejectSessionRequest: function(topic, requestId, error) { - root.store.rejectTransaction(topic, requestId, error) + if (!d.sessionRequests.has(requestId)) { + root.sessionRequestUserAnswerResult(topic, requestId, false, "Unknown request method") + console.error("Session request not found") + return + } + const event = d.sessionRequests.get(requestId) + if (event.params.request.method === SessionRequest.methods.sendTransaction.name) { + root.store.rejectTransaction(topic, requestId, error) + } else if (event.params.request.method === SessionRequest.methods.personalSign.name) { + root.store.rejectPersonalSign(topic, requestId) + } else { + root.sessionRequestUserAnswerResult(topic, requestId, false, "Unknown request method") + console.error("Unknown request method", event.params.request.method) + } } disconnectSession: function(topic) { @@ -182,7 +249,34 @@ WalletConnectSDKBase { return sessionTemplate(dappUrl, dappName, dappIcon, proposalId, eipAccount, eipChains) } - function buildSessionRequest(requestId, topic, chainId, method, txArgs) { + function buildTransactionRequest(requestId, topic, chainId, txArgs) { + var paramsObj = {} + if (txArgs.gasPrice) { + paramsObj.gasPrice = txArgs.gasPrice + } + if (txArgs.gas) { + paramsObj.gasLimit = txArgs.gas + } + if (txArgs.maxFeePerGas) { + paramsObj.maxFeePerGas = txArgs.maxFeePerGas + } + if (txArgs.maxPriorityFeePerGas) { + paramsObj.maxPriorityFeePerGas = txArgs.maxPriorityFeePerGas + } + if (txArgs.nonce) { + paramsObj.nonce = txArgs.nonce + } + if (!!txArgs.data && txArgs.data !== "0x") { + paramsObj.data = txArgs.data + } + if (txArgs.to) { + paramsObj.to = txArgs.to + } + if (txArgs.from) { + paramsObj.from = txArgs.from + } + paramsObj.value = txArgs.value + return { id: requestId, topic, @@ -191,17 +285,24 @@ WalletConnectSDKBase { request: { method: SessionRequest.methods.sendTransaction.name, params: [ - { - from: txArgs.from, - to: txArgs.to, - value: txArgs.value, - gasLimit: txArgs.gas, - gasPrice: txArgs.gasPrice, - maxFeePerGas: txArgs.maxFeePerGas, - maxPriorityFeePerGas: txArgs.maxPriorityFeePerGas, - nonce: txArgs.nonce, - data: txArgs.data - } + paramsObj + ] + } + } + } + } + + function buildSignRequest(requestId, topic, chainId, challenge, address) { + return { + id: requestId, + topic, + params: { + chainId: `eip155:${chainId}`, + request: { + method: SessionRequest.methods.personalSign.name, + params: [ + challenge, + address ] } } diff --git a/ui/app/AppLayouts/Wallet/services/dapps/plugins/SignRequestPlugin.qml b/ui/app/AppLayouts/Wallet/services/dapps/plugins/SignRequestPlugin.qml index 1b934185a5..aabe239e8c 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/plugins/SignRequestPlugin.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/plugins/SignRequestPlugin.qml @@ -169,7 +169,8 @@ SQUtils.QObject { if (error) { root.signCompleted(topic, id, accept, error) - console.error(`Error accepting session request for topic: ${topic}, id: ${id}, accept: ${accept}, error: ${error}`) + const action = accept ? "accepting" : "rejecting" + console.error(`Error ${action} session request for topic: ${topic}, id: ${id}, accept: ${accept}, error: ${error}`) return } diff --git a/ui/imports/shared/stores/BrowserConnectStore.qml b/ui/imports/shared/stores/BrowserConnectStore.qml index 40a89c498a..61f586a324 100644 --- a/ui/imports/shared/stores/BrowserConnectStore.qml +++ b/ui/imports/shared/stores/BrowserConnectStore.qml @@ -9,7 +9,8 @@ SQUtils.QObject { // Signals driven by the dApp signal connectRequested(string requestId, string dappJson) - signal signRequested(string requestId, string requestJson) + signal sendTransaction(string requestId, string requestJson) + signal personalSign(string requestId, string dappJson) signal connected(string dappJson) signal disconnected(string dappJson) @@ -20,6 +21,8 @@ SQUtils.QObject { signal approveTransactionResponse(string topic, string requestId, bool error) signal rejectTransactionResponse(string topic, string requestId, bool error) + signal approvePersonalSignResponse(string topic, string requestId, bool error) + signal rejectPersonalSignResponse(string topic, string requestId, bool error) function approveConnection(id, account, chainId) { return controller.approveConnection(id, account, chainId) @@ -45,6 +48,14 @@ SQUtils.QObject { return controller.getDApps() } + function approvePersonalSign(topic, requestId, signature) { + return controller.approvePersonalSigning(topic, requestId, signature) + } + + function rejectPersonalSign(topic, requestId) { + return controller.rejectPersonalSigning(topic, requestId) + } + Connections { target: controller @@ -52,8 +63,12 @@ SQUtils.QObject { root.connectRequested(requestId, dappJson) } - function onSignRequested(requestId, requestJson) { - root.signRequested(requestId, requestJson) + function onSendTransaction(requestId, requestJson) { + root.sendTransaction(requestId, requestJson) + } + + function onPersonalSign(requestId, dappJson) { + root.personalSign(requestId, dappJson) } function onConnected(dappJson) { @@ -79,5 +94,13 @@ SQUtils.QObject { function onRejectTransactionResponse(topic, requestId, error) { root.rejectTransactionResponse(topic, requestId, error) } + + function onApprovePersonalSignResponse(topic, requestId, error) { + root.approvePersonalSignResponse(topic, requestId, error) + } + + function onRejectPersonalSignResponse(topic, requestId, error) { + root.rejectPersonalSignResponse(topic, requestId, error) + } } } \ No newline at end of file diff --git a/vendor/status-go b/vendor/status-go index ba2baec26f..43f355a391 160000 --- a/vendor/status-go +++ b/vendor/status-go @@ -1 +1 @@ -Subproject commit ba2baec26fac64fe074b485639e95a7b11e81ae5 +Subproject commit 43f355a391ae2ccf304c9b71a1a6af35a3ddb67e