From 81cbc445b02e25c5a357965b7d825c4d7a5ec057 Mon Sep 17 00:00:00 2001 From: Kamal Teja Date: Wed, 19 Aug 2026 03:10:15 +0530 Subject: [PATCH] fix(ethers,ethers5): restore Coinbase Wallet / Base Account session on page reload --- .changeset/wide-plums-yell.md | 30 ++++++ packages/adapters/ethers/src/client.ts | 15 +++ .../adapters/ethers/src/tests/client.test.ts | 72 +++++++++++++++ packages/adapters/ethers5/src/client.ts | 15 +++ .../adapters/ethers5/src/tests/client.test.ts | 92 +++++++++++++++++++ 5 files changed, 224 insertions(+) create mode 100644 .changeset/wide-plums-yell.md diff --git a/.changeset/wide-plums-yell.md b/.changeset/wide-plums-yell.md new file mode 100644 index 0000000000..a1a3f03e76 --- /dev/null +++ b/.changeset/wide-plums-yell.md @@ -0,0 +1,30 @@ +--- +'@reown/appkit-adapter-ethers5': patch +'@reown/appkit-adapter-ethers': patch +'@reown/appkit': patch +'@reown/appkit-adapter-bitcoin': patch +'@reown/appkit-adapter-solana': patch +'@reown/appkit-adapter-ton': patch +'@reown/appkit-adapter-tron': patch +'@reown/appkit-adapter-wagmi': patch +'@reown/appkit-utils': patch +'@reown/appkit-cdn': patch +'@reown/appkit-cli': patch +'@reown/appkit-codemod': patch +'@reown/appkit-common': patch +'@reown/appkit-controllers': patch +'@reown/appkit-core': patch +'@reown/appkit-experimental': patch +'@reown/appkit-pay': patch +'@reown/appkit-polyfills': patch +'@reown/appkit-scaffold-ui': patch +'@reown/appkit-siwe': patch +'@reown/appkit-siwx': patch +'@reown/appkit-testing': patch +'@reown/appkit-ui': patch +'@reown/appkit-universal-connector': patch +'@reown/appkit-wallet': patch +'@reown/appkit-wallet-button': patch +--- + +Fix Coinbase Wallet and Base Account not reconnecting on page reload with ethers and ethers5 adapters diff --git a/packages/adapters/ethers/src/client.ts b/packages/adapters/ethers/src/client.ts index 54413ac8c7..7363e32d90 100644 --- a/packages/adapters/ethers/src/client.ts +++ b/packages/adapters/ethers/src/client.ts @@ -80,11 +80,17 @@ export class EthersAdapter extends AdapterBlueprint { if (enableBaseAccount !== false) { // Do not initialize provider to prevent unnecessary api calls - lazy load this.ethersProviders.baseAccount = new BaseProvider() + if (this.hasStoredConnection(CommonConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)) { + await this.ethersProviders.baseAccount.initialize() + } } if (enableCoinbase !== false) { // Do not initialize provider to prevent unnecessary api calls - lazy load this.ethersProviders.coinbaseWallet = new CoinbaseWalletProvider() + if (this.hasStoredConnection(CommonConstantsUtil.CONNECTOR_ID.COINBASE)) { + await this.ethersProviders.coinbaseWallet.initialize() + } } if (CoreHelperUtil.isSafeApp()) { @@ -101,6 +107,15 @@ export class EthersAdapter extends AdapterBlueprint { } } + private hasStoredConnection(connectorId: string) { + const { hasConnected, hasDisconnected } = HelpersUtil.getConnectorStorageInfo( + connectorId, + this.namespace as ChainNamespace + ) + + return hasConnected && !hasDisconnected + } + public async signMessage( params: AdapterBlueprint.SignMessageParams ): Promise { diff --git a/packages/adapters/ethers/src/tests/client.test.ts b/packages/adapters/ethers/src/tests/client.test.ts index 50a5638336..684f96282d 100644 --- a/packages/adapters/ethers/src/tests/client.test.ts +++ b/packages/adapters/ethers/src/tests/client.test.ts @@ -1431,5 +1431,77 @@ describe('EthersAdapter', () => { expect(providers?.safe).toBeDefined() }) + + it('should initialize coinbase wallet provider if the user was previously connected with it', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: mockEthersConfig.metadata + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockImplementation(connectorId => ({ + hasConnected: connectorId === CommonConstantsUtil.CONNECTOR_ID.COINBASE, + hasDisconnected: false + })) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.coinbaseWallet?.initialize).toHaveBeenCalledTimes(1) + expect(providers?.baseAccount?.initialize).not.toHaveBeenCalled() + }) + + it('should initialize base account provider if the user was previously connected with it', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: mockEthersConfig.metadata + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockImplementation(connectorId => ({ + hasConnected: connectorId === CommonConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, + hasDisconnected: false + })) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.baseAccount?.initialize).toHaveBeenCalledTimes(1) + expect(providers?.coinbaseWallet?.initialize).not.toHaveBeenCalled() + }) + + it('should not initialize coinbase wallet and base account providers if the user was never connected with them', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: mockEthersConfig.metadata + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockReturnValue({ + hasConnected: false, + hasDisconnected: false + }) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.coinbaseWallet?.initialize).not.toHaveBeenCalled() + expect(providers?.baseAccount?.initialize).not.toHaveBeenCalled() + }) + + it('should not initialize coinbase wallet and base account providers if the user explicitly disconnected them', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: mockEthersConfig.metadata + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockReturnValue({ + hasConnected: true, + hasDisconnected: true + }) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.coinbaseWallet?.initialize).not.toHaveBeenCalled() + expect(providers?.baseAccount?.initialize).not.toHaveBeenCalled() + }) }) }) diff --git a/packages/adapters/ethers5/src/client.ts b/packages/adapters/ethers5/src/client.ts index 0c6886450f..774b423c64 100644 --- a/packages/adapters/ethers5/src/client.ts +++ b/packages/adapters/ethers5/src/client.ts @@ -78,11 +78,17 @@ export class Ethers5Adapter extends AdapterBlueprint { if (enableBaseAccount !== false) { // Do not initialize provider to prevent unnecessary api calls - lazy load this.ethersProviders.baseAccount = new BaseProvider() + if (this.hasStoredConnection(CommonConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)) { + await this.ethersProviders.baseAccount.initialize() + } } if (enableCoinbase !== false) { // Do not initialize provider to prevent unnecessary api calls - lazy load this.ethersProviders.coinbaseWallet = new CoinbaseWalletProvider() + if (this.hasStoredConnection(CommonConstantsUtil.CONNECTOR_ID.COINBASE)) { + await this.ethersProviders.coinbaseWallet.initialize() + } } if (CoreHelperUtil.isSafeApp()) { @@ -98,6 +104,15 @@ export class Ethers5Adapter extends AdapterBlueprint { } } + private hasStoredConnection(connectorId: string) { + const { hasConnected, hasDisconnected } = HelpersUtil.getConnectorStorageInfo( + connectorId, + this.namespace as ChainNamespace + ) + + return hasConnected && !hasDisconnected + } + public async signMessage( params: AdapterBlueprint.SignMessageParams ): Promise { diff --git a/packages/adapters/ethers5/src/tests/client.test.ts b/packages/adapters/ethers5/src/tests/client.test.ts index 8e3a7b0471..03c6086762 100644 --- a/packages/adapters/ethers5/src/tests/client.test.ts +++ b/packages/adapters/ethers5/src/tests/client.test.ts @@ -1247,5 +1247,97 @@ describe('Ethers5Adapter', () => { expect(providers?.safe).toBeDefined() }) + + it('should initialize coinbase wallet provider if the user was previously connected with it', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: { + name: 'Test App', + description: 'Test Description', + url: 'https://test.com', + icons: ['https://test.com/icon.png'] + } + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockImplementation(connectorId => ({ + hasConnected: connectorId === CommonConstantsUtil.CONNECTOR_ID.COINBASE, + hasDisconnected: false + })) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.coinbaseWallet?.initialize).toHaveBeenCalledTimes(1) + expect(providers?.baseAccount?.initialize).not.toHaveBeenCalled() + }) + + it('should initialize base account provider if the user was previously connected with it', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: { + name: 'Test App', + description: 'Test Description', + url: 'https://test.com', + icons: ['https://test.com/icon.png'] + } + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockImplementation(connectorId => ({ + hasConnected: connectorId === CommonConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, + hasDisconnected: false + })) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.baseAccount?.initialize).toHaveBeenCalledTimes(1) + expect(providers?.coinbaseWallet?.initialize).not.toHaveBeenCalled() + }) + + it('should not initialize coinbase wallet and base account providers if the user was never connected with them', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: { + name: 'Test App', + description: 'Test Description', + url: 'https://test.com', + icons: ['https://test.com/icon.png'] + } + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockReturnValue({ + hasConnected: false, + hasDisconnected: false + }) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.coinbaseWallet?.initialize).not.toHaveBeenCalled() + expect(providers?.baseAccount?.initialize).not.toHaveBeenCalled() + }) + + it('should not initialize coinbase wallet and base account providers if the user explicitly disconnected them', async () => { + vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({ + ...OptionsController.state, + enableCoinbase: true, + enableBaseAccount: true, + metadata: { + name: 'Test App', + description: 'Test Description', + url: 'https://test.com', + icons: ['https://test.com/icon.png'] + } + }) + vi.spyOn(HelpersUtil, 'getConnectorStorageInfo').mockReturnValue({ + hasConnected: true, + hasDisconnected: true + }) + + const providers = await adapter['createEthersConfig']() + + expect(providers?.coinbaseWallet?.initialize).not.toHaveBeenCalled() + expect(providers?.baseAccount?.initialize).not.toHaveBeenCalled() + }) }) })