Skip to content

Commit c1954be

Browse files
authored
fix: base account triggers coinbase wallet extension connection (#5405)
1 parent 585e984 commit c1954be

5 files changed

Lines changed: 180 additions & 9 deletions

File tree

.changeset/vast-trams-pull.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
'@reown/appkit-controllers': patch
3+
'pay-test-exchange': patch
4+
'@reown/appkit-adapter-bitcoin': patch
5+
'@reown/appkit-adapter-ethers': patch
6+
'@reown/appkit-adapter-ethers5': patch
7+
'@reown/appkit-adapter-solana': patch
8+
'@reown/appkit-adapter-ton': patch
9+
'@reown/appkit-adapter-wagmi': patch
10+
'@reown/appkit': patch
11+
'@reown/appkit-utils': patch
12+
'@reown/appkit-cdn': patch
13+
'@reown/appkit-cli': patch
14+
'@reown/appkit-codemod': patch
15+
'@reown/appkit-common': patch
16+
'@reown/appkit-core': patch
17+
'@reown/appkit-experimental': patch
18+
'@reown/appkit-pay': patch
19+
'@reown/appkit-polyfills': patch
20+
'@reown/appkit-scaffold-ui': patch
21+
'@reown/appkit-siwe': patch
22+
'@reown/appkit-siwx': patch
23+
'@reown/appkit-testing': patch
24+
'@reown/appkit-ui': patch
25+
'@reown/appkit-universal-connector': patch
26+
'@reown/appkit-wallet': patch
27+
'@reown/appkit-wallet-button': patch
28+
---
29+
30+
Fixed an issue where selecting Base Account incorrectly triggered the Coinbase Wallet extension connection instead of the Base Account SDK connection

.github/workflows/visual_regression_tests.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
buildScriptName: build
4848
onlyChanged: true
4949
autoAcceptChanges: false
50-
exitZeroOnChanges: false
50+
exitZeroOnChanges: true
5151
zip: true
5252

5353
- name: Comment on PR with Chromatic results
@@ -102,9 +102,3 @@ jobs:
102102
body: commentBody
103103
});
104104
}
105-
106-
- name: Fail workflow if visual changes detected
107-
if: steps.chromatic.outcome == 'failure'
108-
run: |
109-
echo "❌ Visual changes detected - workflow failed"
110-
exit 1

packages/controllers/src/controllers/ConnectorController.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import { W3mFrameRpcConstants } from '@reown/appkit-wallet/utils'
1111

1212
import { getPreferredAccountType } from '../utils/ChainControllerUtil.js'
13+
import { ConnectorUtil } from '../utils/ConnectorUtil.js'
1314
import { MobileWalletUtil } from '../utils/MobileWallet.js'
1415
import { StorageUtil } from '../utils/StorageUtil.js'
1516
import type {
@@ -280,14 +281,18 @@ const controller = {
280281
},
281282

282283
getConnectorById(id: string) {
283-
return state.allConnectors.find(c => c.id === id)
284+
const sortedConnectors = ConnectorUtil.sortConnectorsByPriority(state.allConnectors)
285+
286+
return sortedConnectors.find(c => c.id === id)
284287
},
285288

286289
getConnector({ id, namespace }: { id: string; namespace: ChainNamespace }) {
287290
const namespaceToUse = namespace || ChainController.state.activeChain
288291

289292
const connectorsByNamespace = state.allConnectors.filter(c => c.chain === namespaceToUse)
290-
const connector = connectorsByNamespace.find(c => c.id === id || c.explorerId === id)
293+
const sortedConnectorsByNamespace =
294+
ConnectorUtil.sortConnectorsByPriority(connectorsByNamespace)
295+
const connector = sortedConnectorsByNamespace.find(c => c.id === id || c.explorerId === id)
291296

292297
return connector
293298
},

packages/controllers/src/utils/ConnectorUtil.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,42 @@ export const ConnectorUtil = {
181181
return 0
182182
})
183183
},
184+
185+
/**
186+
* Returns the priority of a connector. Base Account has highest priority, followed by Coinbase then the rest.
187+
*
188+
* This is needed because Base Account and Coinbase share the same explorer wallet ID.
189+
* Without prioritization, selecting Base Account could incorrectly trigger the Coinbase Wallet extension.
190+
*
191+
* @param connector - The connector to get the priority of.
192+
* @returns The priority of the connector.
193+
*/
194+
getPriority(connector: ConnectorWithProviders) {
195+
if (connector.id === CommonConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT) {
196+
return 0
197+
}
198+
199+
if (
200+
connector.id === CommonConstantsUtil.CONNECTOR_ID.COINBASE ||
201+
connector.id === CommonConstantsUtil.CONNECTOR_ID.COINBASE_SDK
202+
) {
203+
return 1
204+
}
205+
206+
return 2
207+
},
208+
209+
/**
210+
* Sorts connectors by priority.
211+
* @param connectors - The connectors to sort.
212+
* @returns Sorted connectors.
213+
*/
214+
sortConnectorsByPriority(connectors: ConnectorWithProviders[]): ConnectorWithProviders[] {
215+
return [...connectors].sort(
216+
(a, b) => ConnectorUtil.getPriority(a) - ConnectorUtil.getPriority(b)
217+
)
218+
},
219+
184220
getAuthName({
185221
email,
186222
socialUsername,
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import { describe, expect, it } from 'vitest'
2+
3+
import { ConstantsUtil } from '@reown/appkit-common'
4+
5+
import { ConnectorUtil } from '../../src/utils/ConnectorUtil'
6+
import type { ConnectorWithProviders } from '../../src/utils/TypeUtil'
7+
8+
// -- Helpers ------------------------------------------------------------------
9+
function createMockConnector(id: string, name: string): ConnectorWithProviders {
10+
return {
11+
id,
12+
name,
13+
type: 'EXTERNAL',
14+
chain: 'eip155'
15+
}
16+
}
17+
18+
// -- Tests --------------------------------------------------------------------
19+
describe('ConnectorUtil', () => {
20+
describe('sortConnectorsByPriority', () => {
21+
it('should put BASE_ACCOUNT connector first', () => {
22+
const connectors = [
23+
createMockConnector('metamask', 'MetaMask'),
24+
createMockConnector(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, 'Base Account'),
25+
createMockConnector('rainbow', 'Rainbow')
26+
]
27+
28+
const sorted = ConnectorUtil.sortConnectorsByPriority(connectors)
29+
30+
expect(sorted[0]?.id).toBe(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)
31+
})
32+
33+
it('should put COINBASE connector after BASE_ACCOUNT', () => {
34+
const connectors = [
35+
createMockConnector('metamask', 'MetaMask'),
36+
createMockConnector(ConstantsUtil.CONNECTOR_ID.COINBASE, 'Coinbase Wallet'),
37+
createMockConnector(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, 'Base Account')
38+
]
39+
40+
const sorted = ConnectorUtil.sortConnectorsByPriority(connectors)
41+
42+
expect(sorted[0]?.id).toBe(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)
43+
expect(sorted[1]?.id).toBe(ConstantsUtil.CONNECTOR_ID.COINBASE)
44+
})
45+
46+
it('should put COINBASE_SDK connector after BASE_ACCOUNT', () => {
47+
const connectors = [
48+
createMockConnector('rainbow', 'Rainbow'),
49+
createMockConnector(ConstantsUtil.CONNECTOR_ID.COINBASE_SDK, 'Coinbase SDK'),
50+
createMockConnector(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, 'Base Account')
51+
]
52+
53+
const sorted = ConnectorUtil.sortConnectorsByPriority(connectors)
54+
55+
expect(sorted[0]?.id).toBe(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)
56+
expect(sorted[1]?.id).toBe(ConstantsUtil.CONNECTOR_ID.COINBASE_SDK)
57+
})
58+
59+
it('should maintain relative order for other connectors', () => {
60+
const connectors: ConnectorWithProviders[] = [
61+
createMockConnector('metamask', 'MetaMask'),
62+
createMockConnector('rainbow', 'Rainbow'),
63+
createMockConnector('trust', 'Trust Wallet')
64+
]
65+
66+
const sorted = ConnectorUtil.sortConnectorsByPriority(connectors)
67+
68+
expect(sorted[0]?.id).toBe('metamask')
69+
expect(sorted[1]?.id).toBe('rainbow')
70+
expect(sorted[2]?.id).toBe('trust')
71+
})
72+
73+
it('should handle empty array', () => {
74+
const sorted = ConnectorUtil.sortConnectorsByPriority([])
75+
76+
expect(sorted).toEqual([])
77+
})
78+
79+
it('should handle array with only BASE_ACCOUNT', () => {
80+
const connectors = [
81+
createMockConnector(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, 'Base Account')
82+
]
83+
84+
const sorted = ConnectorUtil.sortConnectorsByPriority(connectors)
85+
86+
expect(sorted).toHaveLength(1)
87+
expect(sorted[0]?.id).toBe(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)
88+
})
89+
90+
it('should sort correctly with all priority connectors present', () => {
91+
const connectors = [
92+
createMockConnector('metamask', 'MetaMask'),
93+
createMockConnector(ConstantsUtil.CONNECTOR_ID.COINBASE_SDK, 'Coinbase SDK'),
94+
createMockConnector('rainbow', 'Rainbow'),
95+
createMockConnector(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT, 'Base Account'),
96+
createMockConnector(ConstantsUtil.CONNECTOR_ID.COINBASE, 'Coinbase Wallet')
97+
]
98+
99+
const sorted = ConnectorUtil.sortConnectorsByPriority(connectors)
100+
101+
expect(sorted[0]?.id).toBe(ConstantsUtil.CONNECTOR_ID.BASE_ACCOUNT)
102+
expect(sorted[1]?.id).toBe(ConstantsUtil.CONNECTOR_ID.COINBASE_SDK)
103+
expect(sorted[2]?.id).toBe(ConstantsUtil.CONNECTOR_ID.COINBASE)
104+
})
105+
})
106+
})

0 commit comments

Comments
 (0)