From a310b8b8031b8499d65954504db2e8d3b0c5b228 Mon Sep 17 00:00:00 2001 From: Roman Chornii Date: Mon, 29 Jul 2024 17:39:56 +0300 Subject: [PATCH] fix(dApps): Improved logic for disconnecting of dApps in the app. (#15840) Closes: #15814 --- .../qmlTests/tests/tst_DAppsWorkflow.qml | 118 +++++++++--------- .../services/dapps/DAppsListProvider.qml | 10 +- .../services/dapps/DAppsRequestHandler.qml | 24 ++-- .../services/dapps/DappsConnectorSDK.qml | 12 +- .../services/dapps/WalletConnectService.qml | 33 ++--- .../AppLayouts/Wallet/services/dapps/qmldir | 2 +- 6 files changed, 100 insertions(+), 99 deletions(-) diff --git a/storybook/qmlTests/tests/tst_DAppsWorkflow.qml b/storybook/qmlTests/tests/tst_DAppsWorkflow.qml index 1eb7aaeb4e..10a43cbaa2 100644 --- a/storybook/qmlTests/tests/tst_DAppsWorkflow.qml +++ b/storybook/qmlTests/tests/tst_DAppsWorkflow.qml @@ -270,17 +270,17 @@ Item { } function test_onSessionRequestEventDifferentCaseForAddress() { - let sdk = handler.sdk + const sdk = handler.sdk - let testAddressUpper = "0x3A" - let chainId = 2 - let method = "personal_sign" - let message = "hello world" - let params = [`"${Helpers.strToHex(message)}"`, `"${testAddressUpper}"`] - let topic = "b536a" - let session = JSON.parse(Testing.formatSessionRequest(chainId, method, params, topic)) + const testAddressUpper = "0x3A" + const chainId = 2 + const method = "personal_sign" + const message = "hello world" + const params = [`"${DAppsHelpers.strToHex(message)}"`, `"${testAddressUpper}"`] + const topic = "b536a" + const session = JSON.parse(Testing.formatSessionRequest(chainId, method, params, topic)) // Expect to have calls to getActiveSessions from service initialization - let prevRequests = sdk.getActiveSessionsCallbacks.length + const prevRequests = sdk.getActiveSessionsCallbacks.length sdk.sessionRequestEvent(session) compare(sdk.getActiveSessionsCallbacks.length, 1, "expected DAppsRequestHandler call sdk.getActiveSessions") @@ -288,17 +288,17 @@ Item { // Tests that the request is ignored if not in the current profile (don't have the PK for the address) function test_onSessionRequestEventMissingAddress() { - let sdk = handler.sdk + const sdk = handler.sdk - let testAddressUpper = "0xY" - let chainId = 2 - let method = "personal_sign" - let message = "hello world" - let params = [`"${Helpers.strToHex(message)}"`, `"${testAddressUpper}"`] - let topic = "b536a" - let session = JSON.parse(Testing.formatSessionRequest(chainId, method, params, topic)) + const testAddressUpper = "0xY" + const chainId = 2 + const method = "personal_sign" + const message = "hello world" + const params = [`"${DAppsHelpers.strToHex(message)}"`, `"${testAddressUpper}"`] + const topic = "b536a" + const session = JSON.parse(Testing.formatSessionRequest(chainId, method, params, topic)) // Expect to have calls to getActiveSessions from service initialization - let prevRequests = sdk.getActiveSessionsCallbacks.length + const prevRequests = sdk.getActiveSessionsCallbacks.length sdk.sessionRequestEvent(session) compare(sdk.getActiveSessionsCallbacks.length, 0, "expected DAppsRequestHandler don't call sdk.getActiveSessions") @@ -514,27 +514,27 @@ Item { function test_SessionRequestMainFlow() { // All calls to SDK are expected as events to be made by the wallet connect SDK - let sdk = service.wcSDK - let walletStore = service.walletRootStore - let store = service.store + const sdk = service.wcSDK + const walletStore = service.walletRootStore + const store = service.store - let testAddress = "0x3a" - let chainId = 2 - let method = "personal_sign" - let message = "hello world" - let params = [`"${Helpers.strToHex(message)}"`, `"${testAddress}"`] - let topic = "b536a" - let session = JSON.parse(Testing.formatSessionRequest(chainId, method, params, topic)) + const testAddress = "0x3a" + const chainId = 2 + const method = "personal_sign" + const message = "hello world" + const params = [`"${DAppsHelpers.strToHex(message)}"`, `"${testAddress}"`] + const topic = "b536a" + const session = JSON.parse(Testing.formatSessionRequest(chainId, method, params, topic)) // Expect to have calls to getActiveSessions from service initialization - let prevRequests = sdk.getActiveSessionsCallbacks.length + const prevRequests = sdk.getActiveSessionsCallbacks.length sdk.sessionRequestEvent(session) compare(sdk.getActiveSessionsCallbacks.length, prevRequests + 1, "expected DAppsRequestHandler call sdk.getActiveSessions") - let callback = sdk.getActiveSessionsCallbacks[prevRequests].callback + const callback = sdk.getActiveSessionsCallbacks[prevRequests].callback callback({"b536a": JSON.parse(Testing.formatApproveSessionResponse([chainId, 7], [testAddress]))}) compare(sessionRequestSpy.count, 1, "expected service.sessionRequest trigger") - let request = sessionRequestSpy.signalArguments[0][sessionRequestSpy.argPos.request] + const request = sessionRequestSpy.signalArguments[0][sessionRequestSpy.argPos.request] compare(request.topic, topic, "expected topic to be set") compare(request.method, method, "expected method to be set") compare(request.event, session, "expected event to be the one sent by the sdk") @@ -619,7 +619,7 @@ Item { name: "ServiceHelpers" function test_extractChainsAndAccountsFromApprovedNamespaces() { - let res = Helpers.extractChainsAndAccountsFromApprovedNamespaces(JSON.parse(`{ + const res = DAppsHelpers.extractChainsAndAccountsFromApprovedNamespaces(JSON.parse(`{ "eip155": { "accounts": [ "eip155:1:0x1", @@ -660,25 +660,25 @@ Item { } function test_buildSupportedNamespacesFromModels() { - let methods = ["eth_sendTransaction", "personal_sign"] - let resStr = Helpers.buildSupportedNamespacesFromModels(chainsModel, accountsModel, methods) - let jsonObj = JSON.parse(resStr) + const methods = ["eth_sendTransaction", "personal_sign"] + const resStr = DAppsHelpers.buildSupportedNamespacesFromModels(chainsModel, accountsModel, methods) + const jsonObj = JSON.parse(resStr) verify(jsonObj.hasOwnProperty("eip155")) - let eip155 = jsonObj.eip155 + const eip155 = jsonObj.eip155 verify(eip155.hasOwnProperty("chains")) - let chains = eip155.chains + const chains = eip155.chains verify(chains.length === 2) verify(chains[0] === "eip155:1") verify(chains[1] === "eip155:2") verify(eip155.hasOwnProperty("accounts")) - let accounts = eip155.accounts + const accounts = eip155.accounts verify(accounts.length === 4) for (let chainI = 0; chainI < chainsModel.count; chainI++) { for (let accountI = 0; accountI < chainsModel.count; accountI++) { var found = false - for (let entry of accounts) { + for (const entry of accounts) { if(entry === `eip155:${chainsModel.get(chainI).chainId}:${accountsModel.get(accountI).address}`) { found = true break @@ -709,7 +709,7 @@ Item { "b538c": unknownSession2, "b539d": unknownSessionWithKnownAccount } - let res = Helpers.filterActiveSessionsForKnownAccounts(testSessions, accountsModel) + const res = DAppsHelpers.filterActiveSessionsForKnownAccounts(testSessions, accountsModel) compare(Object.keys(res).length, 2, "expected two sessions to be returned") // Also test that order is stable compare(res["b536a"], knownSession, "expected the known session to be returned") @@ -882,29 +882,29 @@ Item { } function mockSessionRequestEvent(tc, sdk, accountsModel, networksModel) { - let account = accountsModel.get(1) - let network = networksModel.get(1) - let method = "personal_sign" - let message = "hello world" - let params = [`"${Helpers.strToHex(message)}"`, `"${account.address}"`] - let topic = "b536a" - let requestEvent = JSON.parse(Testing.formatSessionRequest(network.chainId, method, params, topic)) - let request = tc.createTemporaryObject(sessionRequestComponent, root, { - event: requestEvent, - topic, - id: requestEvent.id, - method: Constants.personal_sign, - account, - network, - data: message, - preparedData: message + const account = accountsModel.get(1) + const network = networksModel.get(1) + const method = "personal_sign" + const message = "hello world" + const params = [`"${DAppsHelpers.strToHex(message)}"`, `"${account.address}"`] + const topic = "b536a" + const requestEvent = JSON.parse(Testing.formatSessionRequest(network.chainId, method, params, topic)) + const request = tc.createTemporaryObject(sessionRequestComponent, root, { + event: requestEvent, + topic, + id: requestEvent.id, + method: Constants.personal_sign, + account, + network, + data: message, + preparedData: message }) // Expect to have calls to getActiveSessions from service initialization - let prevRequests = sdk.getActiveSessionsCallbacks.length + const prevRequests = sdk.getActiveSessionsCallbacks.length sdk.sessionRequestEvent(requestEvent) // Service might trigger a sessionRequest event following the getActiveSessions call - let callback = sdk.getActiveSessionsCallbacks[prevRequests].callback - let session = JSON.parse(Testing.formatApproveSessionResponse([network.chainId, 7], [account.address])) + const callback = sdk.getActiveSessionsCallbacks[prevRequests].callback + const session = JSON.parse(Testing.formatApproveSessionResponse([network.chainId, 7], [account.address])) callback({"b536a": session}) return {sdk, session, account, network, topic, request} diff --git a/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml b/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml index a4989f52be..26cd50e36c 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/DAppsListProvider.qml @@ -54,9 +54,9 @@ QObject { let tmpMap = {} var topics = [] - const sessions = Helpers.filterActiveSessionsForKnownAccounts(allSessions, root.supportedAccountsModel) - for (let key in sessions) { - let dapp = sessions[key].peer.metadata + const sessions = DAppsHelpers.filterActiveSessionsForKnownAccounts(allSessions, root.supportedAccountsModel) + for (const key in sessions) { + const dapp = sessions[key].peer.metadata if (!!dapp.icons && dapp.icons.length > 0) { dapp.iconUrl = dapp.icons[0] } else { @@ -68,7 +68,7 @@ QObject { // TODO #15075: on SDK dApps refresh update the model that has data source from persistence instead of using reset dapps.clear(); // Iterate tmpMap and fill dapps - for (let key in tmpMap) { + for (const key in tmpMap) { dapps.append(tmpMap[key]); } @@ -87,4 +87,4 @@ QObject { } } } -} \ No newline at end of file +} diff --git a/ui/app/AppLayouts/Wallet/services/dapps/DAppsRequestHandler.qml b/ui/app/AppLayouts/Wallet/services/dapps/DAppsRequestHandler.qml index 7ff61337aa..3cdf3a4eae 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/DAppsRequestHandler.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/DAppsRequestHandler.qml @@ -263,7 +263,7 @@ SQUtils.QObject { if (SessionRequest.getSupportedMethods().includes(method) === false) { return null } - let chainId = Helpers.chainIdFromEip155(event.params.chainId) + const chainId = DAppsHelpers.chainIdFromEip155(event.params.chainId) return SQUtils.ModelUtils.getByKey(root.networksModel, "chainId", chainId) } @@ -280,11 +280,11 @@ SQUtils.QObject { return null } let message = "" - let messageIndex = (method === SessionRequest.methods.personalSign.name ? 0 : 1) - let messageParam = event.params.request.params[messageIndex] + const messageIndex = (method === SessionRequest.methods.personalSign.name ? 0 : 1) + const messageParam = event.params.request.params[messageIndex] // There is no standard on how data is encoded. Therefore we support hex or utf8 - if (Helpers.isHex(messageParam)) { - message = Helpers.hexToString(messageParam) + if (DAppsHelpers.isHex(messageParam)) { + message = DAppsHelpers.hexToString(messageParam) } else { message = messageParam } @@ -295,22 +295,22 @@ SQUtils.QObject { 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 + const jsonMessage = event.params.request.params[1] + const 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] + const 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] + const tx = event.params.request.params[0] return SessionRequest.methods.sendTransaction.buildDataObject(tx) } else { return null @@ -659,4 +659,4 @@ SQUtils.QObject { SessionRequestResolved { } } -} \ 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 93da40aeaa..3838c47d15 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/DappsConnectorSDK.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/DappsConnectorSDK.qml @@ -156,7 +156,7 @@ WalletConnectSDKBase { if (SessionRequest.getSupportedMethods().includes(method) === false) { return null } - let chainId = Helpers.chainIdFromEip155(event.params.chainId) + const chainId = DAppsHelpers.chainIdFromEip155(event.params.chainId) return SQUtils.ModelUtils.getByKey(networksModule.flatNetworks, "chainId", chainId) } @@ -167,13 +167,13 @@ WalletConnectSDKBase { 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 + let message = "" + const messageIndex = (method === SessionRequest.methods.personalSign.name ? 0 : 1) + const 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) + if (DAppsHelpers.isHex(messageParam)) { + message = DAppsHelpers.hexToString(messageParam) } else { message = messageParam } diff --git a/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml b/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml index 259be4fb92..dfca0c10d5 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml +++ b/ui/app/AppLayouts/Wallet/services/dapps/WalletConnectService.qml @@ -56,24 +56,24 @@ QObject { if(Constants.regularExpressions.emoji.test(uri)) { root.pairingValidated(Pairing.errors.tooCool) return - } else if(!Helpers.validURI(uri)) { + } else if(!DAppsHelpers.validURI(uri)) { root.pairingValidated(Pairing.errors.invalidUri) return } - let info = Helpers.extractInfoFromPairUri(uri) + const info = DAppsHelpers.extractInfoFromPairUri(uri) wcSDK.getActiveSessions((sessions) => { // Check if the URI is already paired - var validationState = Pairing.errors.uriOk - for (let key in sessions) { - if (sessions[key].pairingTopic == info.topic) { + let validationState = Pairing.errors.uriOk + for (const key in sessions) { + if (sessions[key].pairingTopic === info.topic) { validationState = Pairing.errors.alreadyUsed break } } // Check if expired - if (validationState == Pairing.errors.uriOk) { + if (validationState === Pairing.errors.uriOk) { const now = (new Date().getTime())/1000 if (info.expiry < now) { validationState = Pairing.errors.expired @@ -92,8 +92,8 @@ QObject { function approvePairSession(sessionProposal, approvedChainIds, approvedAccount) { d.acceptedSessionProposal = sessionProposal - let approvedNamespaces = JSON.parse( - Helpers.buildSupportedNamespaces(approvedChainIds, + const approvedNamespaces = JSON.parse( + DAppsHelpers.buildSupportedNamespaces(approvedChainIds, [approvedAccount.address], SessionRequest.getSupportedMethods()) ) @@ -110,11 +110,12 @@ QObject { function disconnectDapp(url) { wcSDK.getActiveSessions((allSessions) => { - const sessions = Helpers.filterActiveSessionsForKnownAccounts(allSessions, d.supportedAccountsModel) - for (let session in sessions) { - let dapp = session.peer.metadata - let topic = session.topic - if (dapp.url == url) { + const sessions = DAppsHelpers.filterActiveSessionsForKnownAccounts(allSessions, d.supportedAccountsModel) + for (const sessionID in sessions) { + const session = sessions[sessionID] + const dapp = session.peer.metadata + const topic = session.topic + if (dapp.url === url) { wcSDK.disconnectSession(topic) } } @@ -145,8 +146,8 @@ QObject { function onSessionProposal(sessionProposal) { d.currentSessionProposal = sessionProposal - let supportedNamespacesStr = Helpers.buildSupportedNamespacesFromModels( - root.flatNetworks, root.validAccounts, SessionRequest.getSupportedMethods()) + const supportedNamespacesStr = DAppsHelpers.buildSupportedNamespacesFromModels( + root.flatNetworks, root.validAccounts, SessionRequest.getSupportedMethods()) wcSDK.buildApprovedNamespaces(sessionProposal.params, JSON.parse(supportedNamespacesStr)) } @@ -169,7 +170,7 @@ QObject { if (d.acceptedSessionProposal) { wcSDK.approveSession(d.acceptedSessionProposal, approvedNamespaces) } else { - let res = Helpers.extractChainsAndAccountsFromApprovedNamespaces(approvedNamespaces) + const res = DAppsHelpers.extractChainsAndAccountsFromApprovedNamespaces(approvedNamespaces) root.connectDApp(res.chains, d.currentSessionProposal, approvedNamespaces) } diff --git a/ui/app/AppLayouts/Wallet/services/dapps/qmldir b/ui/app/AppLayouts/Wallet/services/dapps/qmldir index 34a25042c4..9391c09251 100644 --- a/ui/app/AppLayouts/Wallet/services/dapps/qmldir +++ b/ui/app/AppLayouts/Wallet/services/dapps/qmldir @@ -6,4 +6,4 @@ DappsConnectorSDK 1.0 DappsConnectorSDK.qml DAppsListProvider 1.0 DAppsListProvider.qml DAppsRequestHandler 1.0 DAppsRequestHandler.qml -Helpers 1.0 helpers.js \ No newline at end of file +DAppsHelpers 1.0 helpers.js