From 1086727e024bafbbebe0059635c4d8728a7fb6b9 Mon Sep 17 00:00:00 2001 From: Enes Date: Fri, 20 Sep 2024 18:30:05 +0300 Subject: [PATCH] refactor/switch network and local storage controls (#2888) --- .changeset/three-doors-love.md | 38 ++++++++ .../src/components/AppKitNetworkInfo.tsx | 2 +- .../src/components/Wagmi/WagmiModalInfo.tsx | 4 +- apps/laboratory/tests/wallet.spec.ts | 17 +++- packages/adapters/ethers/src/client.ts | 26 ++---- .../adapters/ethers/src/tests/client.test.ts | 6 +- packages/adapters/ethers5/src/client.ts | 14 +-- .../adapters/ethers5/src/tests/client.test.ts | 4 +- packages/adapters/solana/src/client.ts | 5 - packages/adapters/wagmi/src/client.ts | 3 - .../src/connectors/UniversalConnector.ts | 5 +- packages/appkit/src/client.ts | 92 ++++++++++--------- packages/appkit/src/tests/appkit.test.ts | 2 +- .../src/tests/universal-adapter.test.ts | 3 +- .../appkit/src/universal-adapter/client.ts | 44 ++++----- packages/common/src/utils/CaipNetworksUtil.ts | 55 ++++++++++- packages/common/src/utils/SafeLocalStorage.ts | 20 +--- .../common/tests/SafeLocalStorage.test.ts | 20 ++-- .../core/src/controllers/ChainController.ts | 92 +++++++++++-------- .../src/controllers/ConnectionController.ts | 2 +- .../core/src/controllers/NetworkController.ts | 25 ----- packages/core/src/utils/StorageUtil.ts | 15 ++- .../controllers/NetworkController.test.ts | 14 --- packages/core/tests/utils/StorageUtil.test.ts | 12 +-- .../scaffold-ui/src/modal/w3m-modal/index.ts | 7 +- .../src/modal/w3m-network-button/index.ts | 11 ++- .../w3m-connecting-external-view/index.ts | 19 +++- .../w3m-connecting-multi-chain-view/index.ts | 1 - 28 files changed, 313 insertions(+), 245 deletions(-) create mode 100644 .changeset/three-doors-love.md diff --git a/.changeset/three-doors-love.md b/.changeset/three-doors-love.md new file mode 100644 index 0000000000..e055c5a083 --- /dev/null +++ b/.changeset/three-doors-love.md @@ -0,0 +1,38 @@ +--- +'@reown/appkit-adapter-ethers5': patch +'@reown/appkit-adapter-ethers': patch +'@reown/appkit-adapter-solana': patch +'@reown/appkit-adapter-wagmi': patch +'@reown/appkit-scaffold-ui': patch +'@apps/laboratory': patch +'@reown/appkit': patch +'@reown/appkit-common': patch +'@reown/appkit-core': patch +'@apps/demo': patch +'@apps/gallery': patch +'@examples/html-ethers': patch +'@examples/html-ethers5': patch +'@examples/html-wagmi': patch +'@examples/next-ethers': patch +'@examples/next-wagmi': patch +'@examples/react-ethers': patch +'@examples/react-ethers5': patch +'@examples/react-solana': patch +'@examples/react-wagmi': patch +'@examples/vue-ethers5': patch +'@examples/vue-solana': patch +'@examples/vue-wagmi': patch +'@reown/appkit-adapter-polkadot': patch +'@reown/appkit-utils': patch +'@reown/appkit-cdn': patch +'@reown/appkit-ethers': patch +'@reown/appkit-ethers5': patch +'@reown/appkit-polyfills': patch +'@reown/appkit-siwe': patch +'@reown/appkit-solana': patch +'@reown/appkit-ui': patch +'@reown/appkit-wagmi': patch +'@reown/appkit-wallet': patch +--- + +Updates active network state management and local storage controls diff --git a/apps/laboratory/src/components/AppKitNetworkInfo.tsx b/apps/laboratory/src/components/AppKitNetworkInfo.tsx index cd1f21a33e..20e6b2be71 100644 --- a/apps/laboratory/src/components/AppKitNetworkInfo.tsx +++ b/apps/laboratory/src/components/AppKitNetworkInfo.tsx @@ -27,7 +27,7 @@ export function AppKitNetworkInfo() { Address - {address} + {address || '-'} diff --git a/apps/laboratory/src/components/Wagmi/WagmiModalInfo.tsx b/apps/laboratory/src/components/Wagmi/WagmiModalInfo.tsx index fa3ffa62c7..227db333c8 100644 --- a/apps/laboratory/src/components/Wagmi/WagmiModalInfo.tsx +++ b/apps/laboratory/src/components/Wagmi/WagmiModalInfo.tsx @@ -13,9 +13,9 @@ export function WagmiModalInfo() { async function getClientId() { if (connector?.type === 'walletConnect') { const provider = await connector?.getProvider?.() - const ethereumProvider = provider as UniversalProvider + const universalProvider = provider as UniversalProvider - return ethereumProvider.client?.core?.crypto?.getClientId() + return universalProvider?.client?.core?.crypto?.getClientId() } return null diff --git a/apps/laboratory/tests/wallet.spec.ts b/apps/laboratory/tests/wallet.spec.ts index 7e22d70590..14bcd30089 100644 --- a/apps/laboratory/tests/wallet.spec.ts +++ b/apps/laboratory/tests/wallet.spec.ts @@ -81,8 +81,23 @@ sampleWalletTest('it should switch networks and sign', async ({ library }) => { await processChain(0) }) +sampleWalletTest('it should show last connected network after refreshing', async ({ library }) => { + const chainName = library === 'solana' ? 'Solana Testnet' : 'Polygon' + + await modalPage.switchNetwork(chainName) + await modalValidator.expectSwitchedNetwork(chainName) + await modalPage.closeModal() + + await modalPage.page.reload() + + await modalPage.openModal() + await modalPage.openNetworks() + await modalValidator.expectSwitchedNetwork(chainName) + await modalPage.closeModal() +}) + sampleWalletTest('it should reject sign', async ({ library }) => { - const chainName = library === 'solana' ? 'Solana' : DEFAULT_CHAIN_NAME + const chainName = library === 'solana' ? 'Solana Testnet' : 'Polygon' await modalPage.sign() await walletValidator.expectReceivedSign({ chainName }) await walletPage.handleRequest({ accept: false }) diff --git a/packages/adapters/ethers/src/client.ts b/packages/adapters/ethers/src/client.ts index 82ad431a6f..7dccf29f2a 100644 --- a/packages/adapters/ethers/src/client.ts +++ b/packages/adapters/ethers/src/client.ts @@ -613,12 +613,10 @@ export class EthersAdapter { if (provider) { const { addresses, chainId } = await EthersHelpersUtil.getUserInfo(provider) const firstAddress = addresses?.[0] - const caipNetwork = this.caipNetworks.find(c => c.chainId === chainId) const caipAddress = `${this.chainNamespace}:${chainId}:${firstAddress}` as CaipAddress - if (firstAddress && chainId && caipNetwork) { + if (firstAddress && chainId) { this.appKit?.setCaipAddress(caipAddress, this.chainNamespace) - this.appKit?.setCaipNetwork(caipNetwork) ProviderUtil.setProviderId('eip155', providerId) ProviderUtil.setProvider('eip155', provider) this.appKit?.setStatus('connected', this.chainNamespace) @@ -660,8 +658,6 @@ export class EthersAdapter { : [{ address, type: preferredAccountType as 'eoa' | 'smartAccount' }], this.chainNamespace ) - const caipNetwork = this.caipNetworks.find(c => c.chainId === chainId) - this.appKit?.setCaipNetwork(caipNetwork) this.appKit?.setStatus('connected', this.chainNamespace) this.appKit?.setCaipAddress( `${this.chainNamespace}:${chainId}:${address}`, @@ -717,13 +713,13 @@ export class EthersAdapter { } } - const chainChangedHandler = (networkId: string) => { - if (networkId) { - const networkIdNumber = - typeof networkId === 'string' - ? EthersHelpersUtil.hexStringToNumber(networkId) - : Number(networkId) - const caipNetwork = this.caipNetworks.find(c => c.chainId === networkIdNumber) + const chainChangedHandler = (chainId: string) => { + const chainIdNumber = + typeof chainId === 'string' ? EthersHelpersUtil.hexStringToNumber(chainId) : Number(chainId) + const caipNetwork = this.caipNetworks.find(c => c.chainId === chainIdNumber) + const currentCaipNetwork = this.appKit?.getCaipNetwork() + + if (!currentCaipNetwork || currentCaipNetwork?.id !== caipNetwork?.id) { this.appKit?.setCaipNetwork(caipNetwork) } } @@ -836,10 +832,7 @@ export class EthersAdapter { this.appKit?.setLoading(true) const chainId = NetworkUtil.caipNetworkIdToNumber(this.appKit?.getCaipNetwork()?.id) - const caipNetwork = this.caipNetworks.find(c => c.chainId === chainId) - this.appKit?.setCaipAddress(`eip155:${chainId}:${address}`, this.chainNamespace) - this.appKit?.setCaipNetwork(caipNetwork) this.appKit?.setStatus('connected', this.chainNamespace) this.appKit?.setPreferredAccountType(type as W3mFrameTypes.AccountType, this.chainNamespace) @@ -1014,13 +1007,12 @@ export class EthersAdapter { } public async switchNetwork(caipNetwork: CaipNetwork) { - const requestSwitchNetwork = async (provider: Provider) => { + async function requestSwitchNetwork(provider: Provider) { try { await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: EthersHelpersUtil.numberToHexString(caipNetwork.chainId) }] }) - this.appKit?.setCaipNetwork(caipNetwork) // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (switchError: any) { if ( diff --git a/packages/adapters/ethers/src/tests/client.test.ts b/packages/adapters/ethers/src/tests/client.test.ts index fa86bac689..b46b9c25b5 100644 --- a/packages/adapters/ethers/src/tests/client.test.ts +++ b/packages/adapters/ethers/src/tests/client.test.ts @@ -165,7 +165,6 @@ describe('EthersAdapter', () => { ]) }) ) - expect(mockAppKit.setCaipNetwork).toHaveBeenCalledWith(newNetwork) }) it('should add network if not recognized by wallet', async () => { @@ -344,7 +343,6 @@ describe('EthersAdapter', () => { expect(mockAppKit.setLoading).toHaveBeenCalledWith(true) expect(mockAppKit.setCaipAddress).toHaveBeenCalledWith(`eip155:${1}:${address}`, 'eip155') - expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() expect(mockAppKit.setStatus).toHaveBeenCalledWith('connected', 'eip155') expect(mockAppKit.setPreferredAccountType).toHaveBeenCalledWith(type, 'eip155') @@ -388,7 +386,6 @@ describe('EthersAdapter', () => { [{ address: mockAddress, type: mockPreferredAccountType }], 'eip155' ) - expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() expect(mockAppKit.setStatus).toHaveBeenCalledWith('connected', 'eip155') expect(mockAppKit.setCaipAddress).toHaveBeenCalledWith( `eip155:${mockChainId}:${mockAddress}`, @@ -527,7 +524,6 @@ describe('EthersAdapter', () => { SafeLocalStorageKeys.WALLET_NAME, 'MetaMask' ) - expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() expect(mockAppKit.setCaipAddress).toHaveBeenCalled() expect(ProviderUtil.setProviderId).toHaveBeenCalledWith('eip155', 'injected') expect(ProviderUtil.setProvider).toHaveBeenCalledWith('eip155', mockProvider) @@ -584,7 +580,7 @@ describe('EthersAdapter', () => { const chainChangedHandler = mockProvider.on.mock.calls.find( (call: string[]) => call[0] === 'chainChanged' )[1] - await chainChangedHandler('0x1') + await chainChangedHandler('0x137') expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() }) diff --git a/packages/adapters/ethers5/src/client.ts b/packages/adapters/ethers5/src/client.ts index b324b14c80..2c69e9b2f0 100644 --- a/packages/adapters/ethers5/src/client.ts +++ b/packages/adapters/ethers5/src/client.ts @@ -722,13 +722,13 @@ export class Ethers5Adapter { } } - const chainChangedHandler = (networkId: string) => { - if (networkId) { - const networkIdNumber = - typeof networkId === 'string' - ? EthersHelpersUtil.hexStringToNumber(networkId) - : Number(networkId) - const caipNetwork = this.caipNetworks.find(c => c.chainId === networkIdNumber) + const chainChangedHandler = (chainId: string) => { + const chainIdNumber = + typeof chainId === 'string' ? EthersHelpersUtil.hexStringToNumber(chainId) : Number(chainId) + const caipNetwork = this.caipNetworks.find(c => c.chainId === chainIdNumber) + const currentCaipNetwork = this.appKit?.getCaipNetwork() + + if (!currentCaipNetwork || currentCaipNetwork?.id !== caipNetwork?.id) { this.appKit?.setCaipNetwork(caipNetwork) } } diff --git a/packages/adapters/ethers5/src/tests/client.test.ts b/packages/adapters/ethers5/src/tests/client.test.ts index a0e57eebb8..3909eea4b6 100644 --- a/packages/adapters/ethers5/src/tests/client.test.ts +++ b/packages/adapters/ethers5/src/tests/client.test.ts @@ -349,7 +349,6 @@ describe('EthersAdapter', () => { expect(mockAppKit.setLoading).toHaveBeenCalledWith(true) expect(mockAppKit.setCaipAddress).toHaveBeenCalledWith(`eip155:${1}:${address}`, 'eip155') - expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() expect(mockAppKit.setStatus).toHaveBeenCalledWith('connected', 'eip155') expect(mockAppKit.setPreferredAccountType).toHaveBeenCalledWith(type, 'eip155') @@ -532,7 +531,6 @@ describe('EthersAdapter', () => { SafeLocalStorageKeys.WALLET_NAME, 'MetaMask' ) - expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() expect(ProviderUtil.setProviderId).toHaveBeenCalledWith('eip155', 'injected') expect(ProviderUtil.setProvider).toHaveBeenCalledWith('eip155', mockProvider) expect(mockAppKit.setStatus).toHaveBeenCalledWith('connected', 'eip155') @@ -588,7 +586,7 @@ describe('EthersAdapter', () => { const chainChangedHandler = mockProvider.on.mock.calls.find( (call: string[]) => call[0] === 'chainChanged' )[1] - await chainChangedHandler('0x1') + await chainChangedHandler('0x2') expect(mockAppKit.setCaipNetwork).toHaveBeenCalled() }) diff --git a/packages/adapters/solana/src/client.ts b/packages/adapters/solana/src/client.ts index b0a4cd9f14..dca682af4c 100644 --- a/packages/adapters/solana/src/client.ts +++ b/packages/adapters/solana/src/client.ts @@ -2,7 +2,6 @@ import { Connection } from '@solana/web3.js' import { AccountController, ApiController, - AssetController, ChainController, CoreHelperUtil, EventsController @@ -311,10 +310,6 @@ export class SolanaAdapter implements ChainAdapter { this.syncRequestedNetworks(this.caipNetworks) - AssetController.subscribeNetworkImages(() => { - this.syncNetwork() - }) - ChainController.subscribeKey('activeCaipNetwork', (newCaipNetwork: CaipNetwork | undefined) => { const newChain = this.caipNetworks.find( _chain => _chain.chainId === newCaipNetwork?.id.split(':')[1] diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 1b134f1c54..36f2d8c598 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -394,7 +394,6 @@ export class WagmiAdapter implements ChainAdapter { await SIWEController.signOut() } SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_ID) - SafeLocalStorage.removeItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) SafeLocalStorage.removeItem(SafeLocalStorageKeys.CONNECTED_CONNECTOR) SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_NAME) this.appKit?.setClientId(null) @@ -609,7 +608,6 @@ export class WagmiAdapter implements ChainAdapter { this.appKit?.resetNetwork() this.appKit?.setAllAccounts([], this.chainNamespace) SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_ID) - SafeLocalStorage.removeItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) return } @@ -647,7 +645,6 @@ export class WagmiAdapter implements ChainAdapter { } } else if (status === 'connected' && address && chainId) { const caipAddress = `eip155:${chainId}:${address}` as CaipAddress - this.appKit?.resetAccount(this.chainNamespace) this.syncNetwork(address, chainId, true) this.appKit?.setCaipAddress(caipAddress, this.chainNamespace) await Promise.all([ diff --git a/packages/adapters/wagmi/src/connectors/UniversalConnector.ts b/packages/adapters/wagmi/src/connectors/UniversalConnector.ts index ec0324c416..38b68d9b4e 100644 --- a/packages/adapters/wagmi/src/connectors/UniversalConnector.ts +++ b/packages/adapters/wagmi/src/connectors/UniversalConnector.ts @@ -19,10 +19,10 @@ import { numberToHex } from 'viem' import { WcHelpersUtil } from '@reown/appkit' +import { StorageUtil } from '@reown/appkit-core' import type { AppKitOptions } from '@reown/appkit' import type { AppKit } from '@reown/appkit' import { convertToAppKitChains } from '../utils/helpers.js' -import { SafeLocalStorage, SafeLocalStorageKeys } from '@reown/appkit-common' type UniversalConnector = Connector & { onDisplayUri(uri: string): void @@ -231,7 +231,8 @@ export function walletConnect(parameters: AppKitOptionsParams, appKit: AppKit) { const currentChainId = appKit.getCaipNetwork()?.chainId if (chainId && currentChainId !== chainId) { - const storedCaipNetwork = SafeLocalStorage.getItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) + const storedCaipNetwork = StorageUtil.getStoredActiveCaipNetwork() + if (storedCaipNetwork && storedCaipNetwork.chainNamespace === 'eip155') { await this.switchChain?.({ chainId: Number(storedCaipNetwork.chainId) }) } else { diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index fbff2654b5..cc5c525ed2 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -32,7 +32,9 @@ import { ConstantsUtil, type CaipNetwork, type ChainNamespace, - CaipNetworksUtil + CaipNetworksUtil, + SafeLocalStorage, + SafeLocalStorageKeys } from '@reown/appkit-common' import type { AppKitOptions } from './utils/TypesUtil.js' import { UniversalAdapterClient } from './universal-adapter/client.js' @@ -292,7 +294,7 @@ export class AppKit { } public setCaipNetwork: (typeof NetworkController)['setCaipNetwork'] = caipNetwork => { - NetworkController.setActiveCaipNetwork(caipNetwork) + ChainController.setActiveCaipNetwork(caipNetwork) } public getCaipNetwork = (chainNamespace?: ChainNamespace) => { @@ -427,32 +429,11 @@ export class AppKit { this.adapters = options.adapters - options.metadata ||= { - name: - typeof document === 'undefined' - ? '' - : document.getElementsByTagName('title')[0]?.textContent || '', - description: - typeof document === 'undefined' - ? '' - : document.querySelector('meta[property="og:description"]')?.content || - '', - url: typeof window === 'undefined' ? '' : window.location.origin, - icons: [ - typeof document === 'undefined' - ? '' - : document.querySelector('link[rel~="icon"]')?.href || '' - ] - } - - options.networks = this.prepareCaipNetworks( - options.networks, - options.chainImages, - options.projectId - ) - + this.setMetadata(options) + this.extendCaipNetworks(options) this.initializeUniversalAdapter(options) this.initializeAdapters(options) + this.setDefaultNetwork(options) OptionsController.setAllWallets(options.allWallets) OptionsController.setIncludeWalletIds(options.includeWalletIds) @@ -498,14 +479,33 @@ export class AppKit { } } + private setMetadata(options: AppKitOptions) { + if (typeof window === 'undefined' || typeof document === 'undefined') { + return + } + + options.metadata = { + name: document.getElementsByTagName('title')[0]?.textContent || '', + description: + document.querySelector('meta[property="og:description"]')?.content || '', + url: window.location.origin, + icons: [document.querySelector('link[rel~="icon"]')?.href || ''] + } + } + + private extendCaipNetworks(options: AppKitOptions) { + options.networks = CaipNetworksUtil.extendCaipNetworks(options.networks, { + networkImageIds: PresetsUtil.NetworkImageIds, + customNetworkImageUrls: options.chainImages, + projectId: options.projectId + }) + options.defaultNetwork = options.networks.find(n => n.id === options.defaultNetwork?.id) + } + private initializeUniversalAdapter(options: AppKitOptions) { this.universalAdapter = new UniversalAdapterClient(options) - ChainController.initializeUniversalAdapter(this.universalAdapter, options.adapters || []) - this.universalAdapter.construct?.(this, options) - - NetworkController.setDefaultCaipNetwork(options.defaultNetwork) } private initializeAdapters(options: AppKitOptions) { @@ -513,11 +513,26 @@ export class AppKit { options.adapters?.forEach(adapter => { // @ts-expect-error will introduce construct later adapter.construct?.(this, options) - - NetworkController.setDefaultCaipNetwork(options.defaultNetwork) }) } + private setDefaultNetwork(options: AppKitOptions) { + const extendedDefaultNetwork = options.defaultNetwork + ? CaipNetworksUtil.extendCaipNetwork(options.defaultNetwork, { + networkImageIds: PresetsUtil.NetworkImageIds, + customNetworkImageUrls: options.chainImages, + projectId: options.projectId + }) + : undefined + const previousNetwork = SafeLocalStorage.getItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID) + const caipNetwork = previousNetwork + ? options.networks.find(n => n.id === previousNetwork) + : undefined + + const network = caipNetwork ?? extendedDefaultNetwork ?? options.networks[0] + ChainController.setActiveCaipNetwork(network) + } + private async initOrContinue() { if (!this.initPromise && !isInitialized && CoreHelperUtil.isClient()) { isInitialized = true @@ -536,17 +551,4 @@ export class AppKit { return this.initPromise } - - private prepareCaipNetworks( - caipNetworks: CaipNetwork[], - caipNetworkImages: Record | undefined, - projectId: string - ): CaipNetwork[] { - return caipNetworks.map(caipNetwork => ({ - ...caipNetwork, - imageId: PresetsUtil.NetworkImageIds[caipNetwork.chainId], - imageUrl: caipNetworkImages?.[caipNetwork.chainId], - rpcUrl: CaipNetworksUtil.extendRpcUrlWithProjectId(caipNetwork.rpcUrl, projectId) - })) - } } diff --git a/packages/appkit/src/tests/appkit.test.ts b/packages/appkit/src/tests/appkit.test.ts index 60782052b9..64e9df1edc 100644 --- a/packages/appkit/src/tests/appkit.test.ts +++ b/packages/appkit/src/tests/appkit.test.ts @@ -276,7 +276,7 @@ describe('Base', () => { it('should set CAIP network', () => { const caipNetwork = { id: 'eip155:1', name: 'Ethereum' } as unknown as CaipNetwork appKit.setCaipNetwork(caipNetwork) - expect(NetworkController.setActiveCaipNetwork).toHaveBeenCalledWith(caipNetwork) + expect(ChainController.setActiveCaipNetwork).toHaveBeenCalledWith(caipNetwork) }) it('should get CAIP network', () => { diff --git a/packages/appkit/src/tests/universal-adapter.test.ts b/packages/appkit/src/tests/universal-adapter.test.ts index 3054521c08..4de82634d9 100644 --- a/packages/appkit/src/tests/universal-adapter.test.ts +++ b/packages/appkit/src/tests/universal-adapter.test.ts @@ -68,8 +68,7 @@ describe('UniversalAdapter', () => { caipNetwork: undefined, requestedCaipNetworks: [mainnet, solana], approvedCaipNetworkIds: [], - supportsAllNetworks: true, - isDefaultCaipNetwork: false + supportsAllNetworks: true }) const adapterSpy = vi.spyOn(universalAdapter as any, 'setDefaultNetwork') diff --git a/packages/appkit/src/universal-adapter/client.ts b/packages/appkit/src/universal-adapter/client.ts index c75c595d5f..8080dbd89e 100644 --- a/packages/appkit/src/universal-adapter/client.ts +++ b/packages/appkit/src/universal-adapter/client.ts @@ -5,6 +5,7 @@ import { ConnectionController, CoreHelperUtil, NetworkController, + StorageUtil, type ConnectionControllerClient, type Connector, type NetworkControllerClient @@ -25,7 +26,6 @@ import type { import { SafeLocalStorage, SafeLocalStorageKeys } from '@reown/appkit-common' import { ProviderUtil } from '../store/index.js' import type { AppKitOptions } from '../utils/TypesUtil.js' -import { allChains } from '../networks/index.js' type Metadata = { name: string @@ -226,7 +226,6 @@ export class UniversalAdapterClient { disconnect: async () => { SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_ID) - SafeLocalStorage.removeItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) if (siweConfig?.options?.signOutOnDisconnect) { const { SIWEController } = await import('@reown/appkit-siwe') @@ -396,7 +395,7 @@ export class UniversalAdapterClient { } }) - const storedCaipNetwork = SafeLocalStorage.getItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) + const storedCaipNetwork = StorageUtil.getStoredActiveCaipNetwork() const activeCaipNetwork = ChainController.state.activeCaipNetwork try { @@ -453,7 +452,6 @@ export class UniversalAdapterClient { ConnectionController.resetWcConnection() SafeLocalStorage.removeItem(SafeLocalStorageKeys.WALLET_ID) - SafeLocalStorage.removeItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) provider?.removeListener('disconnect', disconnectHandler) provider?.removeListener('accountsChanged', accountsChangedHandler) @@ -468,28 +466,24 @@ export class UniversalAdapterClient { const chainChanged = (chainId: number | string) => { // eslint-disable-next-line eqeqeq const caipNetwork = this.caipNetworks.find(c => c.chainId == chainId) - const isSameNetwork = - caipNetwork?.chainId === ChainController.state.activeCaipNetwork?.chainId + const currentCaipNetwork = this.appKit?.getCaipNetwork() + + if (!caipNetwork) { + NetworkController.setActiveCaipNetwork({ + chainId: Number(chainId), + id: `eip155:${chainId}`, + name: 'Unknown Network', + currency: '', + explorerUrl: '', + rpcUrl: '', + chainNamespace: this.appKit?.getActiveChainNamespace() || 'eip155' + }) - if (!isSameNetwork) { - if (caipNetwork) { - NetworkController.setActiveCaipNetwork(caipNetwork) - } else { - const chain = allChains.find(c => c.chainId.toString() === chainId.toString()) - if (chain) { - NetworkController.setActiveCaipNetwork(chain) - } else { - NetworkController.setActiveCaipNetwork({ - chainId: Number(chainId), - id: `eip155:${chainId}`, - name: 'Unknown Network', - currency: '', - explorerUrl: '', - rpcUrl: '', - chainNamespace: this.appKit?.getActiveChainNamespace() || 'eip155' - }) - } - } + return + } + + if (!currentCaipNetwork || currentCaipNetwork?.id !== caipNetwork?.id) { + this.appKit?.setCaipNetwork(caipNetwork) } } diff --git a/packages/common/src/utils/CaipNetworksUtil.ts b/packages/common/src/utils/CaipNetworksUtil.ts index 9d75cc6612..7c968554f7 100644 --- a/packages/common/src/utils/CaipNetworksUtil.ts +++ b/packages/common/src/utils/CaipNetworksUtil.ts @@ -1,5 +1,13 @@ +import type { CaipNetwork } from './TypeUtil.js' + const RPC_URL_HOST = 'rpc.walletconnect.org' +type ExtendCaipNetworkParams = { + networkImageIds: Record + customNetworkImageUrls: Record | undefined + projectId: string +} + export const CaipNetworksUtil = { /** * Extends the RPC URL with the project ID if the RPC URL is a Reown URL @@ -12,11 +20,56 @@ export const CaipNetworksUtil = { if (isReownUrl) { const url = new URL(rpcUrl) - url.searchParams.set('projectId', projectId) + if (!url.searchParams.has('projectId')) { + url.searchParams.set('projectId', projectId) + } return url.toString() } return rpcUrl + }, + + /** + * Extends the CaipNetwork object with the image ID and image URL if the image ID is not provided + * @param params - The parameters object + * @param params.caipNetwork - The CaipNetwork object to extend + * @param params.networkImageIds - The network image IDs + * @param params.customNetworkImageUrls - The custom network image URLs + * @param params.projectId - The project ID + * @returns The extended array of CaipNetwork objects + */ + extendCaipNetwork( + caipNetwork: CaipNetwork, + { networkImageIds, customNetworkImageUrls, projectId }: ExtendCaipNetworkParams + ): CaipNetwork { + return { + ...caipNetwork, + imageId: networkImageIds[caipNetwork.chainId], + imageUrl: customNetworkImageUrls?.[caipNetwork.chainId], + rpcUrl: CaipNetworksUtil.extendRpcUrlWithProjectId(caipNetwork.rpcUrl, projectId) + } + }, + + /** + * Extends the array of CaipNetwork objects with the image ID and image URL if the image ID is not provided + * @param caipNetworks - The array of CaipNetwork objects to extend + * @param params - The parameters object + * @param params.networkImageIds - The network image IDs + * @param params.customNetworkImageUrls - The custom network image URLs + * @param params.projectId - The project ID + * @returns The extended array of CaipNetwork objects + */ + extendCaipNetworks( + caipNetworks: CaipNetwork[], + { networkImageIds, customNetworkImageUrls, projectId }: ExtendCaipNetworkParams + ): CaipNetwork[] { + return caipNetworks.map(caipNetwork => + CaipNetworksUtil.extendCaipNetwork(caipNetwork, { + networkImageIds, + customNetworkImageUrls, + projectId + }) + ) } } diff --git a/packages/common/src/utils/SafeLocalStorage.ts b/packages/common/src/utils/SafeLocalStorage.ts index 56f2697ffd..03957246fe 100644 --- a/packages/common/src/utils/SafeLocalStorage.ts +++ b/packages/common/src/utils/SafeLocalStorage.ts @@ -1,17 +1,14 @@ -import type { CaipNetwork } from './TypeUtil.js' - export type SafeLocalStorageItems = { '@appkit/wallet_id': string '@appkit/wallet_name': string '@appkit/solana_wallet': string '@appkit/solana_caip_chain': string - '@appkit/active_caip_network': CaipNetwork '@appkit/active_caip_network_id': string '@appkit/connected_connector': string '@appkit/connected_social': string '@appkit/connected_social_username': string '@appkit/recent_wallets': string - '@appkit/deeplink_choice': { href: string; name: string } + '@appkit/deeplink_choice': string } export const SafeLocalStorageKeys = { @@ -19,7 +16,6 @@ export const SafeLocalStorageKeys = { WALLET_NAME: '@appkit/wallet_name', SOLANA_WALLET: '@appkit/solana_wallet', SOLANA_CAIP_CHAIN: '@appkit/solana_caip_chain', - ACTIVE_CAIP_NETWORK: '@appkit/active_caip_network', ACTIVE_CAIP_NETWORK_ID: '@appkit/active_caip_network_id', CONNECTED_CONNECTOR: '@appkit/connected_connector', CONNECTED_SOCIAL: '@appkit/connected_social', @@ -34,24 +30,14 @@ export const SafeLocalStorage = { value: SafeLocalStorageItems[Key] ): void { if (isSafe()) { - localStorage.setItem(key, JSON.stringify(value)) + localStorage.setItem(key, value) } }, getItem( key: Key ): SafeLocalStorageItems[Key] | undefined { if (isSafe()) { - const value = localStorage.getItem(key) - - if (value) { - try { - return JSON.parse(value) - } catch (e) { - console.warn('Error parsing value from localStorage', key, e) - - return undefined - } - } + return localStorage.getItem(key) || undefined } return undefined diff --git a/packages/common/tests/SafeLocalStorage.test.ts b/packages/common/tests/SafeLocalStorage.test.ts index c9e2f574dd..369a70f7c8 100644 --- a/packages/common/tests/SafeLocalStorage.test.ts +++ b/packages/common/tests/SafeLocalStorage.test.ts @@ -24,7 +24,13 @@ describe('SafeLocalStorage unsafe', () => { }) describe('SafeLocalStorage safe', () => { - let getItem = vi.fn(() => '{"test":"test"}') + let getItem = vi.fn(value => { + if (value === '@appkit/wallet_id') { + return 'test' + } + + return undefined + }) let setItem = vi.fn() let removeItem = vi.fn() @@ -40,11 +46,11 @@ describe('SafeLocalStorage safe', () => { it('should setItem', () => { expect(SafeLocalStorage.setItem('@appkit/wallet_id', 'test')).toBe(undefined) - expect(setItem).toHaveBeenCalledWith('@appkit/wallet_id', JSON.stringify('test')) + expect(setItem).toHaveBeenCalledWith('@appkit/wallet_id', 'test') }) it('should getItem ', () => { - expect(SafeLocalStorage.getItem('@appkit/wallet_id')).toEqual({ test: 'test' }) + expect(SafeLocalStorage.getItem('@appkit/wallet_id')).toEqual('test') expect(getItem).toHaveBeenCalledWith('@appkit/wallet_id') }) @@ -53,10 +59,8 @@ describe('SafeLocalStorage safe', () => { expect(removeItem).toHaveBeenCalledWith('@appkit/wallet_id') }) - it('getItem should return undefined when value is not valid JSON', () => { - getItem.mockReturnValueOnce('test') - - expect(SafeLocalStorage.getItem('@appkit/wallet_id')).toBe(undefined) - expect(getItem).toHaveBeenCalledWith('@appkit/wallet_id') + it('getItem should return undefined if the value not exist', () => { + expect(SafeLocalStorage.getItem('@appkit/connected_connector')).toBe(undefined) + expect(getItem).toHaveBeenCalledWith('@appkit/connected_connector') }) }) diff --git a/packages/core/src/controllers/ChainController.ts b/packages/core/src/controllers/ChainController.ts index 057cae7b49..ad115e2dea 100644 --- a/packages/core/src/controllers/ChainController.ts +++ b/packages/core/src/controllers/ChainController.ts @@ -12,6 +12,7 @@ import { type CaipNetwork, type ChainNamespace } from '@reown/appkit-common' +import { StorageUtil } from '../utils/StorageUtil.js' // -- Types --------------------------------------------- // export interface ChainControllerState { @@ -48,7 +49,6 @@ const accountState: AccountControllerState = { const networkState: NetworkControllerState = { supportsAllNetworks: true, - isDefaultCaipNetwork: false, smartAccountEnabledNetworks: [] } @@ -106,7 +106,6 @@ export const ChainController = { if (!state.noAdapters) { state.activeChain = adapterToActivate?.chainNamespace PublicStateController.set({ activeChain: adapterToActivate?.chainNamespace }) - this.setActiveCaipNetwork(adapterToActivate?.defaultNetwork) adapters.forEach((adapter: ChainsInitializerAdapter) => { state.chains.set(adapter.chainNamespace, { @@ -129,16 +128,14 @@ export const ChainController = { state.universalAdapter = adapter if (adapters.length === 0) { - const storedCaipNetwork = SafeLocalStorage.getItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK) + const storedCaipNetwork = StorageUtil.getStoredActiveCaipNetwork() try { if (storedCaipNetwork) { state.activeChain = storedCaipNetwork.chainNamespace - this.setActiveCaipNetwork(storedCaipNetwork) } else { state.activeChain = adapter?.defaultNetwork?.chainNamespace ?? adapter.caipNetworks[0]?.chainNamespace - this.setActiveCaipNetwork(adapter?.defaultNetwork ?? adapter.caipNetworks[0]) } } catch (error) { console.warn('>>> Error setting active caip network', error) @@ -157,8 +154,6 @@ export const ChainController = { caipNetworks: adapter.caipNetworks }) }) - - this.setActiveChain(adapter.chainNamespace) }, setChainNetworkData( @@ -227,27 +222,35 @@ export const ChainController = { ) }, - setActiveChain( + setActiveNamespace( chain: ChainNamespace | undefined, caipNetwork?: NetworkControllerState['caipNetwork'] ) { - const newAdapter = chain ? state.chains.get(chain) : undefined - - if (newAdapter && newAdapter.chainNamespace !== state.activeChain) { - state.activeChain = newAdapter.chainNamespace - state.activeCaipAddress = newAdapter.accountState?.caipAddress - state.activeCaipNetwork = caipNetwork - - if (!newAdapter.accountState) { - this.resetAccount(newAdapter.chainNamespace) + if (caipNetwork?.chainNamespace) { + const newAdapter = chain ? state.chains.get(caipNetwork.chainNamespace) : undefined + const newNamespace = newAdapter?.chainNamespace !== state.activeChain + + if (newAdapter && newNamespace) { + state.activeChain = newAdapter.chainNamespace + state.activeCaipNetwork = caipNetwork + state.activeCaipAddress = newAdapter.accountState?.caipAddress + SafeLocalStorage.setItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID, caipNetwork.id) + + NetworkController.replaceState(newAdapter.networkState) + AccountController.replaceState(newAdapter.accountState) + + PublicStateController.set({ + activeChain: chain, + selectedNetworkId: newAdapter.networkState?.caipNetwork?.id + }) } - - NetworkController.replaceState(newAdapter.networkState) - AccountController.replaceState(newAdapter.accountState) - + } else { + state.activeChain = chain + const caipNetworks = chain ? state.chains.get(chain)?.caipNetworks : [] + state.activeCaipNetwork = caipNetworks?.[0] PublicStateController.set({ activeChain: chain, - selectedNetworkId: newAdapter.networkState?.caipNetwork?.id + selectedNetworkId: state.activeCaipNetwork?.id }) } }, @@ -257,23 +260,19 @@ export const ChainController = { return } - if (caipNetwork.chainNamespace !== state.activeChain) { - this.setActiveChain(caipNetwork.chainNamespace, caipNetwork) - SafeLocalStorage.setItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK, caipNetwork) - SafeLocalStorage.setItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID, caipNetwork.id) + const sameNamespace = caipNetwork.chainNamespace === state.activeChain - return + if (sameNamespace) { + state.activeChain = caipNetwork.chainNamespace + state.activeCaipNetwork = caipNetwork + PublicStateController.set({ + activeChain: state.activeChain, + selectedNetworkId: state.activeCaipNetwork?.id + }) + SafeLocalStorage.setItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID, caipNetwork.id) + } else { + this.setActiveNamespace(caipNetwork.chainNamespace, caipNetwork) } - - state.activeCaipNetwork = caipNetwork - state.activeChain = caipNetwork.chainNamespace - PublicStateController.set({ - activeChain: caipNetwork.chainNamespace, - selectedNetworkId: caipNetwork?.id - }) - - SafeLocalStorage.setItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK, caipNetwork) - SafeLocalStorage.setItem(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID, caipNetwork.id) }, /** @@ -289,8 +288,12 @@ export const ChainController = { caipNetwork: NetworkControllerState['caipNetwork'], shouldReplace = false ) { - state.activeCaipNetwork = caipNetwork state.activeChain = caipNetwork?.chainNamespace + state.activeCaipNetwork = caipNetwork + PublicStateController.set({ + activeChain: state.activeChain, + selectedNetworkId: state.activeCaipNetwork?.id + }) this.setChainNetworkData(chain, { caipNetwork }, shouldReplace) }, @@ -409,6 +412,19 @@ export const ChainController = { return chainNetworkState[key] }, + getAllRequestedCaipNetworks(): NetworkControllerState['requestedCaipNetworks'] { + const requestedCaipNetworks: NetworkControllerState['requestedCaipNetworks'] = [] + + state.chains.forEach(chainAdapter => { + const chainNetworkState = chainAdapter.networkState + if (chainNetworkState?.requestedCaipNetworks) { + requestedCaipNetworks.push(...chainNetworkState.requestedCaipNetworks) + } + }) + + return requestedCaipNetworks + }, + getAllApprovedCaipNetworks(): NetworkControllerState['approvedCaipNetworkIds'] { const approvedCaipNetworkIds: NetworkControllerState['approvedCaipNetworkIds'] = [] diff --git a/packages/core/src/controllers/ConnectionController.ts b/packages/core/src/controllers/ConnectionController.ts index d2db45f1ee..520bfa5c0f 100644 --- a/packages/core/src/controllers/ConnectionController.ts +++ b/packages/core/src/controllers/ConnectionController.ts @@ -98,7 +98,7 @@ export const ConnectionController = { async connectExternal(options: ConnectExternalOptions, chain: ChainNamespace, setChain = true) { await this._getClient(chain).connectExternal?.(options) if (setChain) { - ChainController.setActiveChain(chain) + ChainController.setActiveNamespace(chain) StorageUtil.setConnectedConnector(options.type) } }, diff --git a/packages/core/src/controllers/NetworkController.ts b/packages/core/src/controllers/NetworkController.ts index 3bab3f3f32..8a222ab8e5 100644 --- a/packages/core/src/controllers/NetworkController.ts +++ b/packages/core/src/controllers/NetworkController.ts @@ -9,7 +9,6 @@ import { type ChainNamespace } from '@reown/appkit-common' import { ChainController } from './ChainController.js' -import { PublicStateController } from './PublicStateController.js' import { ConstantsUtil } from '../utils/ConstantsUtil.js' // -- Types --------------------------------------------- // @@ -23,7 +22,6 @@ export interface NetworkControllerClient { export interface NetworkControllerState { supportsAllNetworks: boolean - isDefaultCaipNetwork: boolean isUnsupportedChain?: boolean _client?: NetworkControllerClient caipNetwork?: CaipNetwork @@ -36,7 +34,6 @@ export interface NetworkControllerState { // -- State --------------------------------------------- // const state = proxy({ supportsAllNetworks: true, - isDefaultCaipNetwork: false, smartAccountEnabledNetworks: [] }) @@ -73,24 +70,6 @@ export const NetworkController = { return ChainController.getNetworkControllerClient() }, - initializeDefaultNetwork() { - const networks = this.getRequestedCaipNetworks() - - if (networks.length > 0) { - this.setCaipNetwork(networks[0]) - } - }, - - setDefaultCaipNetwork(caipNetwork: NetworkControllerState['caipNetwork']) { - if (caipNetwork) { - ChainController.setCaipNetwork(caipNetwork.chainNamespace, caipNetwork) - ChainController.setChainNetworkData(caipNetwork.chainNamespace, { - isDefaultCaipNetwork: true - }) - PublicStateController.set({ selectedNetworkId: caipNetwork.id }) - } - }, - setActiveCaipNetwork(caipNetwork: NetworkControllerState['caipNetwork']) { if (!caipNetwork) { return @@ -277,10 +256,6 @@ export const NetworkController = { throw new Error('chain is required to reset network') } - if (!ChainController.state.chains.get(chain)?.networkState?.isDefaultCaipNetwork) { - ChainController.setChainNetworkData(chain, { caipNetwork: undefined }) - } - ChainController.setChainNetworkData(chain, { approvedCaipNetworkIds: undefined, supportsAllNetworks: true, diff --git a/packages/core/src/utils/StorageUtil.ts b/packages/core/src/utils/StorageUtil.ts index f1b9ff8dd6..7ba4d4e657 100644 --- a/packages/core/src/utils/StorageUtil.ts +++ b/packages/core/src/utils/StorageUtil.ts @@ -1,12 +1,13 @@ /* eslint-disable no-console */ import { SafeLocalStorage, SafeLocalStorageKeys } from '@reown/appkit-common' import type { WcWallet, ConnectorType, SocialProvider } from './TypeUtil.js' +import { ChainController } from '../controllers/ChainController.js' // -- Utility ----------------------------------------------------------------- export const StorageUtil = { - setWalletConnectDeepLink({ href, name }: { href: string; name: string }) { + setWalletConnectDeepLink({ href }: { href: string; name: string }) { try { - SafeLocalStorage.setItem(SafeLocalStorageKeys.DEEPLINK_CHOICE, { href, name }) + SafeLocalStorage.setItem(SafeLocalStorageKeys.DEEPLINK_CHOICE, href) } catch { console.info('Unable to set WalletConnect deep link') } @@ -105,5 +106,15 @@ export const StorageUtil = { } return undefined + }, + + getStoredActiveCaipNetwork() { + const storedCaipNetworkId = SafeLocalStorage.getItem( + SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID + ) + const allRequestedCaipNetworks = ChainController.getAllRequestedCaipNetworks() + const storedCaipNetwork = allRequestedCaipNetworks?.find(c => c.id === storedCaipNetworkId) + + return storedCaipNetwork } } diff --git a/packages/core/tests/controllers/NetworkController.test.ts b/packages/core/tests/controllers/NetworkController.test.ts index df23bec31d..ee0874713d 100644 --- a/packages/core/tests/controllers/NetworkController.test.ts +++ b/packages/core/tests/controllers/NetworkController.test.ts @@ -89,7 +89,6 @@ describe('NetworkController', () => { expect(NetworkController.state).toEqual({ supportsAllNetworks: true, - isDefaultCaipNetwork: false, smartAccountEnabledNetworks: [] }) }) @@ -116,19 +115,6 @@ describe('NetworkController', () => { expect(NetworkController.state.smartAccountEnabledNetworks).toEqual([]) }) - it('should update state correctly on setDefaultCaipNetwork()', () => { - NetworkController.setDefaultCaipNetwork(caipNetwork) - expect(NetworkController.state.caipNetwork).toEqual(caipNetwork) - expect(NetworkController.state.isDefaultCaipNetwork).toEqual(true) - }) - - it('should reset state correctly when default caip network is true', () => { - NetworkController.resetNetwork() - expect(NetworkController.state.caipNetwork).toEqual(caipNetwork) - expect(NetworkController.state.approvedCaipNetworkIds).toEqual(undefined) - expect(NetworkController.state.requestedCaipNetworks).toEqual(requestedCaipNetworks) - }) - it('should check correctly if smart accounts are enabled on the network', () => { NetworkController.setActiveCaipNetwork(caipNetwork) NetworkController.setSmartAccountEnabledNetworks([1], chain) diff --git a/packages/core/tests/utils/StorageUtil.test.ts b/packages/core/tests/utils/StorageUtil.test.ts index 5095c69998..30dd3de7f6 100644 --- a/packages/core/tests/utils/StorageUtil.test.ts +++ b/packages/core/tests/utils/StorageUtil.test.ts @@ -46,8 +46,7 @@ describe('StorageUtil', () => { const deepLink = { href: 'https://example.com', name: 'Example Wallet' } StorageUtil.setWalletConnectDeepLink(deepLink) const savedDL = SafeLocalStorage.getItem(SafeLocalStorageKeys.DEEPLINK_CHOICE) - expect(savedDL?.href).toBe(deepLink.href) - expect(savedDL?.name).toBe(deepLink.name) + expect(savedDL).toBe(deepLink.href) }) it('should handle errors when setting deep link', () => { @@ -64,8 +63,8 @@ describe('StorageUtil', () => { describe('getWalletConnectDeepLink', () => { it('should get WalletConnect deep link from localStorage', () => { const deepLink = { href: 'https://example.com', name: 'Example Wallet' } - SafeLocalStorage.setItem('@appkit/deeplink_choice', deepLink) - expect(StorageUtil.getWalletConnectDeepLink()).toEqual(deepLink) + SafeLocalStorage.setItem('@appkit/deeplink_choice', deepLink.href) + expect(StorageUtil.getWalletConnectDeepLink()).toEqual(deepLink.href) }) it('should return undefined if deep link is not set', () => { @@ -85,10 +84,7 @@ describe('StorageUtil', () => { describe('deleteWalletConnectDeepLink', () => { it('should delete WalletConnect deep link from localStorage', () => { - SafeLocalStorage.setItem('@appkit/deeplink_choice', { - href: 'https://example.com', - name: 'Example Wallet' - }) + SafeLocalStorage.setItem('@appkit/deeplink_choice', 'https://example.com') StorageUtil.deleteWalletConnectDeepLink() expect(SafeLocalStorage.getItem('@appkit/deeplink_choice')).toBeUndefined() }) diff --git a/packages/scaffold-ui/src/modal/w3m-modal/index.ts b/packages/scaffold-ui/src/modal/w3m-modal/index.ts index ab7c86403d..61c10a518a 100644 --- a/packages/scaffold-ui/src/modal/w3m-modal/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-modal/index.ts @@ -192,8 +192,9 @@ export class W3mModal extends LitElement { ? CoreHelperUtil.getPlainAddress(this.caipAddress) : undefined const nextConnected = caipAddress ? CoreHelperUtil.getPlainAddress(caipAddress) : undefined + const isSameAddress = prevConnected === nextConnected - if (this.isSiweEnabled) { + if (nextConnected && !isSameAddress && this.isSiweEnabled) { const { SIWEController } = await import('@reown/appkit-siwe') const signed = AccountController.state.siweStatus === 'success' @@ -207,6 +208,10 @@ export class W3mModal extends LitElement { } } + if (!nextConnected) { + ModalController.close() + } + this.caipAddress = caipAddress } diff --git a/packages/scaffold-ui/src/modal/w3m-network-button/index.ts b/packages/scaffold-ui/src/modal/w3m-network-button/index.ts index c915679eb2..bd82658073 100644 --- a/packages/scaffold-ui/src/modal/w3m-network-button/index.ts +++ b/packages/scaffold-ui/src/modal/w3m-network-button/index.ts @@ -36,7 +36,8 @@ export class W3mNetworkButton extends LitElement { @state() private isUnsupportedChain = NetworkController.state.isUnsupportedChain // -- Lifecycle ----------------------------------------- // - public override firstUpdated() { + public constructor() { + super() this.unsubscribe.push( ...[ AssetController.subscribeNetworkImages(() => { @@ -79,6 +80,10 @@ export class W3mNetworkButton extends LitElement { // -- Private ------------------------------------------- // private getLabel() { + if (this.network) { + return this.network.name + } + if (this.label) { return this.label } @@ -87,10 +92,6 @@ export class W3mNetworkButton extends LitElement { return 'Switch Network' } - if (this.network) { - return this.network.name - } - if (this.caipAddress) { return 'Unknown Network' } diff --git a/packages/scaffold-ui/src/views/w3m-connecting-external-view/index.ts b/packages/scaffold-ui/src/views/w3m-connecting-external-view/index.ts index efca0da308..d93de9c20b 100644 --- a/packages/scaffold-ui/src/views/w3m-connecting-external-view/index.ts +++ b/packages/scaffold-ui/src/views/w3m-connecting-external-view/index.ts @@ -11,6 +11,9 @@ import { W3mConnectingWidget } from '../../utils/w3m-connecting-widget/index.js' @customElement('w3m-connecting-external-view') export class W3mConnectingExternalView extends W3mConnectingWidget { + // -- Members ------------------------------------------- // + private externalViewUnsubscribe: (() => void)[] = [] + public constructor() { super() if (!this.connector) { @@ -28,11 +31,17 @@ export class W3mConnectingExternalView extends W3mConnectingWidget { this.onConnect = this.onConnectProxy.bind(this) this.onAutoConnect = this.onConnectProxy.bind(this) this.isWalletConnect = false - ChainController.subscribeKey('activeCaipAddress', val => { - if (val) { - ModalController.close() - } - }) + this.externalViewUnsubscribe.push( + ChainController.subscribeKey('activeCaipAddress', val => { + if (val) { + ModalController.close() + } + }) + ) + } + + public override disconnectedCallback() { + this.externalViewUnsubscribe.forEach(unsubscribe => unsubscribe()) } // -- Private ------------------------------------------- // diff --git a/packages/scaffold-ui/src/views/w3m-connecting-multi-chain-view/index.ts b/packages/scaffold-ui/src/views/w3m-connecting-multi-chain-view/index.ts index 4fcbb86fa0..661d2ab6a0 100644 --- a/packages/scaffold-ui/src/views/w3m-connecting-multi-chain-view/index.ts +++ b/packages/scaffold-ui/src/views/w3m-connecting-multi-chain-view/index.ts @@ -92,7 +92,6 @@ export class W3mConnectingMultiChainView extends LitElement { } private onConnector(provider: Connector) { - ChainController.setActiveChain(provider.chain) const connector = this.activeConnector?.connectors?.find(p => p.chain === provider.chain) if (!connector) {