From 69fcf27c56db900554eacced0b1725c3060ed781 Mon Sep 17 00:00:00 2001 From: Felipe Mendes Date: Mon, 16 Dec 2024 19:35:55 -0300 Subject: [PATCH] fix: universal provider accounts changed event (#3462) Co-authored-by: tomiir --- .changeset/swift-melons-cover.md | 22 +++++++++++++++++ packages/appkit/src/client.ts | 18 +++++++++++++- .../src/tests/utils/HelpersUtil.test.ts | 23 ++++++++++++++++++ packages/appkit/src/utils/HelpersUtil.ts | 24 +++++++++++++++++++ packages/core/src/utils/CoreHelperUtil.ts | 14 +++++++++++ .../core/tests/utils/CoreHelperUtil.test.ts | 14 +++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 .changeset/swift-melons-cover.md diff --git a/.changeset/swift-melons-cover.md b/.changeset/swift-melons-cover.md new file mode 100644 index 0000000000..202e1506df --- /dev/null +++ b/.changeset/swift-melons-cover.md @@ -0,0 +1,22 @@ +--- +'@reown/appkit': patch +'@reown/appkit-core': patch +'@reown/appkit-adapter-ethers': patch +'@reown/appkit-adapter-ethers5': patch +'@reown/appkit-adapter-solana': patch +'@reown/appkit-adapter-wagmi': patch +'@reown/appkit-utils': patch +'@reown/appkit-cdn': patch +'@reown/appkit-cli': patch +'@reown/appkit-common': patch +'@reown/appkit-experimental': patch +'@reown/appkit-polyfills': patch +'@reown/appkit-scaffold-ui': patch +'@reown/appkit-siwe': patch +'@reown/appkit-siwx': patch +'@reown/appkit-ui': patch +'@reown/appkit-wallet': patch +'@reown/appkit-wallet-button': patch +--- + +Adds parsing of Universal Provider session_event to get accountsChanged event diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index bbd31ce715..aecc9c58c5 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -55,7 +55,8 @@ import { type ChainNamespace, type CaipAddress, type CaipNetworkId, - NetworkUtil + NetworkUtil, + ParseUtil } from '@reown/appkit-common' import type { AppKitOptions } from './utils/TypesUtil.js' import { @@ -81,6 +82,7 @@ import UniversalProvider from '@walletconnect/universal-provider' import type { SessionTypes } from '@walletconnect/types' import type { UniversalProviderOpts } from '@walletconnect/universal-provider' import { W3mFrameProviderSingleton } from './auth-provider/W3MFrameProviderSingleton.js' +import { WcHelpersUtil } from './utils/HelpersUtil.js' declare global { interface Window { @@ -1286,6 +1288,20 @@ export class AppKit { this.setCaipNetwork(caipNetwork) } }) + + this.universalProvider.on('session_event', (callbackData: unknown) => { + if (WcHelpersUtil.isSessionEventData(callbackData)) { + const { name, data } = callbackData.params.event + + if ( + name === 'accountsChanged' && + Array.isArray(data) && + CoreHelperUtil.isCaipAddress(data[0]) + ) { + this.syncAccount(ParseUtil.parseCaipAddress(data[0])) + } + } + }) } } diff --git a/packages/appkit/src/tests/utils/HelpersUtil.test.ts b/packages/appkit/src/tests/utils/HelpersUtil.test.ts index b490a443fa..d6d31507cc 100644 --- a/packages/appkit/src/tests/utils/HelpersUtil.test.ts +++ b/packages/appkit/src/tests/utils/HelpersUtil.test.ts @@ -205,4 +205,27 @@ describe('WcHelpersUtil', () => { ]) }) }) + + describe('isSessionEventData', () => { + test.each([ + [undefined, false], + [{}, false], + [ + { + id: 1734112958243866, + topic: 'b2cb2748499532d9c307846c444b364dd881c959d9a080e30d63b6a76270a0f8', + params: { + event: { + name: 'accountsChanged', + data: ['eip155:1:0x53F31e8972Ebddac1553E37887C25C1b748485A6'] + }, + chainId: 'eip155:1' + } + }, + true + ] + ])('should validate session event data', (data, expected) => { + expect(WcHelpersUtil.isSessionEventData(data)).toBe(expected) + }) + }) }) diff --git a/packages/appkit/src/utils/HelpersUtil.ts b/packages/appkit/src/utils/HelpersUtil.ts index 601aea1a06..932f2336bb 100644 --- a/packages/appkit/src/utils/HelpersUtil.ts +++ b/packages/appkit/src/utils/HelpersUtil.ts @@ -101,5 +101,29 @@ export const WcHelpersUtil = { return Array.from(new Set([...chains, ...accountsChains])) }) + }, + + isSessionEventData(data: unknown): data is WcHelpersUtil.SessionEventData { + return ( + typeof data === 'object' && + data !== null && + 'id' in data && + 'topic' in data && + 'params' in data && + typeof data.params === 'object' && + data.params !== null && + 'chainId' in data.params && + 'event' in data.params && + typeof data.params.event === 'object' && + data.params.event !== null + ) + } +} + +export namespace WcHelpersUtil { + export type SessionEventData = { + id: string + topic: string + params: { chainId: string; event: { data: unknown; name: string } } } } diff --git a/packages/core/src/utils/CoreHelperUtil.ts b/packages/core/src/utils/CoreHelperUtil.ts index 1034800e25..86498fc39d 100644 --- a/packages/core/src/utils/CoreHelperUtil.ts +++ b/packages/core/src/utils/CoreHelperUtil.ts @@ -357,5 +357,19 @@ export const CoreHelperUtil = { address, type } as AccountTypeMap[N] + }, + + isCaipAddress(address?: unknown): address is CaipAddress { + if (typeof address !== 'string') { + return false + } + + const sections = address.split(':') + const namespace = sections[0] + + return ( + sections.filter(Boolean).length === 3 && + (namespace as string) in CommonConstants.CHAIN_NAME_MAP + ) } } diff --git a/packages/core/tests/utils/CoreHelperUtil.test.ts b/packages/core/tests/utils/CoreHelperUtil.test.ts index b3f4c69112..54fd3f8160 100644 --- a/packages/core/tests/utils/CoreHelperUtil.test.ts +++ b/packages/core/tests/utils/CoreHelperUtil.test.ts @@ -57,4 +57,18 @@ describe('CoreHelperUtil', () => { global.window.self = originalSelf } }) + + it.each([ + [undefined, false], + [{}, false], + ['0x0', false], + ['eip155::mock_address', false], + ['eip155:mock_chain_id:', false], + ['invalid_namespace:mock_chain_id:address', false], + ['eip155:mock_chain_id:mock_address', true], + ['solana:mock_chain_id:mock_address', true], + ['bip122:mock_chain_id:mock_address', true] + ])('should validate the value $s is valid caip address $b', (caipAddress, expected) => { + expect(CoreHelperUtil.isCaipAddress(caipAddress)).toEqual(expected) + }) })