Skip to content

Commit fe1ec95

Browse files
feat: support eip6963 (#510)
* feat: support eip6963 * feat: support eip6963 * fix: wallets repeat * test: add test case * fix: hide get btn when not has app and extensions config * fix: EIP6963Config type bug * fix: EIP6963Config type bug * test: add test case * docs: update demo --------- Co-authored-by: beilunyang <[email protected]>
1 parent b233b31 commit fe1ec95

File tree

16 files changed

+655
-54
lines changed

16 files changed

+655
-54
lines changed

.changeset/lucky-suns-perform.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@ant-design/web3-wagmi': minor
3+
'@ant-design/web3': minor
4+
---
5+
6+
feat: support EIP6963 wallet

packages/wagmi/src/interface.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,9 @@ export interface WalletFactory {
1111
connectors: Connector['name'][];
1212
create: (connector?: readonly Connector[]) => WalletUseInWagmiAdapter;
1313
}
14+
15+
export type EIP6963Config =
16+
| boolean
17+
| {
18+
autoAddInjectedWallets?: boolean;
19+
};

packages/wagmi/src/utils.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import debug from 'debug';
2+
import type { Connector as WagmiConnector } from 'wagmi';
3+
import { injected } from 'wagmi/connectors';
24

35
const createDebug = (namespace: string) => {
46
return debug(`antd-web3:wagmi:${namespace}`);
57
};
68

7-
export { createDebug };
9+
const isEIP6963Connector = (connector: WagmiConnector) => {
10+
if (connector.type === injected.type && connector.icon && connector.id && connector.name) {
11+
return true;
12+
}
13+
return false;
14+
};
15+
16+
export { createDebug, isEIP6963Connector };
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import { ConnectButton, Connector } from '@ant-design/web3';
2+
import { ChromeCircleColorful } from '@ant-design/web3-icons';
3+
import { MetaMask, UniversalWallet, WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi';
4+
import { fireEvent, render } from '@testing-library/react';
5+
import { describe, expect, it, vi } from 'vitest';
6+
import { createConfig, http } from 'wagmi';
7+
import { mainnet } from 'wagmi/chains';
8+
import { injected } from 'wagmi/connectors';
9+
10+
const mockConnectAsync = vi.fn();
11+
12+
vi.mock('wagmi', async () => {
13+
const actual = await vi.importActual('wagmi');
14+
return {
15+
...actual,
16+
useConnect: () => {
17+
return {
18+
connectAsync: async (...args: any[]) => {
19+
mockConnectAsync(...args);
20+
},
21+
};
22+
},
23+
};
24+
});
25+
26+
describe('WagmiWeb3ConfigProvider with EIP6963 and custom wallets', () => {
27+
it('Should use user config wallet', async () => {
28+
const target1 = {
29+
icon: 'icon1',
30+
id: 'com.mock.wallet1',
31+
name: 'mockWallet1',
32+
provider: {
33+
request: () => {},
34+
on: () => {},
35+
} as any,
36+
};
37+
38+
const target2 = {
39+
icon: 'icon2',
40+
id: 'com.mock.wallet2',
41+
name: 'mockWallet2',
42+
provider: {
43+
request: () => {},
44+
on: () => {},
45+
} as any,
46+
};
47+
48+
const mockDiscoveredConnectorsViaEIP6963 = [
49+
injected({
50+
target: 'metaMask',
51+
}),
52+
injected({
53+
target: target1,
54+
}),
55+
injected({
56+
target: target2,
57+
}),
58+
];
59+
60+
const config = createConfig({
61+
chains: [mainnet],
62+
transports: {
63+
[mainnet.id]: http(),
64+
},
65+
connectors: mockDiscoveredConnectorsViaEIP6963,
66+
});
67+
68+
const App = () => (
69+
<WagmiWeb3ConfigProvider
70+
wallets={[
71+
new UniversalWallet({
72+
extensions: [
73+
{
74+
key: 'Chrome',
75+
browserIcon: <ChromeCircleColorful />,
76+
browserName: 'Chrome',
77+
link: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
78+
description: 'Access your wallet right from your favorite web browser.',
79+
},
80+
],
81+
name: 'mockWallet1',
82+
remark: 'mockWallet1',
83+
icon: 'http://userconfig.com/icon',
84+
}),
85+
]}
86+
eip6963={{
87+
autoAddInjectedWallets: true,
88+
}}
89+
config={config}
90+
>
91+
<Connector>
92+
<ConnectButton />
93+
</Connector>
94+
</WagmiWeb3ConfigProvider>
95+
);
96+
const { baseElement } = render(<App />);
97+
const btn = baseElement.querySelector('.ant-web3-connect-button');
98+
fireEvent.click(btn!);
99+
const walletItems = baseElement.querySelectorAll('.ant-web3-connect-modal-wallet-item');
100+
expect(walletItems.length).toBe(2);
101+
expect(walletItems[0].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
102+
target1.name,
103+
);
104+
expect(walletItems[1].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
105+
target2.name,
106+
);
107+
expect(
108+
walletItems[0].querySelector('.ant-web3-connect-modal-icon > img')?.getAttribute('src'),
109+
).toBe('http://userconfig.com/icon');
110+
expect(
111+
walletItems[1].querySelector('.ant-web3-connect-modal-icon > img')?.getAttribute('src'),
112+
).toBe(target2.icon);
113+
const groupTitle = baseElement.querySelector('.ant-web3-connect-modal-group-title');
114+
expect(groupTitle?.textContent).toBe('More');
115+
116+
fireEvent.click(walletItems[0]!);
117+
await vi.waitFor(() => {
118+
expect(mockConnectAsync).toHaveBeenCalledWith({
119+
connector: config.connectors[1],
120+
chainId: config.chains[0].id,
121+
});
122+
});
123+
});
124+
125+
it('Should use user config connector when not find with eip6963', async () => {
126+
const target1 = {
127+
icon: 'icon1',
128+
id: 'com.mock.wallet1',
129+
name: 'mockWallet1',
130+
provider: {
131+
request: () => {},
132+
on: () => {},
133+
} as any,
134+
};
135+
136+
const target2 = {
137+
icon: 'icon2',
138+
id: 'com.mock.wallet2',
139+
name: 'mockWallet2',
140+
provider: {
141+
request: () => {},
142+
on: () => {},
143+
} as any,
144+
};
145+
146+
const mockDiscoveredConnectorsViaEIP6963 = [
147+
injected({
148+
target: 'metaMask',
149+
}),
150+
injected({
151+
target: target1,
152+
}),
153+
injected({
154+
target: target2,
155+
}),
156+
];
157+
158+
const config = createConfig({
159+
chains: [mainnet],
160+
transports: {
161+
[mainnet.id]: http(),
162+
},
163+
connectors: mockDiscoveredConnectorsViaEIP6963,
164+
});
165+
166+
const App = () => (
167+
<WagmiWeb3ConfigProvider
168+
wallets={[
169+
new UniversalWallet({
170+
extensions: [
171+
{
172+
key: 'Chrome',
173+
browserIcon: <ChromeCircleColorful />,
174+
browserName: 'Chrome',
175+
link: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
176+
description: 'Access your wallet right from your favorite web browser.',
177+
},
178+
],
179+
name: 'mockWallet1',
180+
remark: 'mockWallet1',
181+
icon: 'http://userconfig.com/icon',
182+
}),
183+
MetaMask(),
184+
]}
185+
eip6963={{
186+
autoAddInjectedWallets: true,
187+
}}
188+
config={config}
189+
>
190+
<Connector>
191+
<ConnectButton />
192+
</Connector>
193+
</WagmiWeb3ConfigProvider>
194+
);
195+
const { baseElement } = render(<App />);
196+
const btn = baseElement.querySelector('.ant-web3-connect-button');
197+
fireEvent.click(btn!);
198+
const walletItems = baseElement.querySelectorAll('.ant-web3-connect-modal-wallet-item');
199+
expect(walletItems.length).toBe(3);
200+
expect(walletItems[0].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
201+
'MetaMask',
202+
);
203+
expect(walletItems[1].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
204+
target1.name,
205+
);
206+
expect(walletItems[2].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
207+
target2.name,
208+
);
209+
expect(
210+
walletItems[1].querySelector('.ant-web3-connect-modal-icon > img')?.getAttribute('src'),
211+
).toBe('http://userconfig.com/icon');
212+
expect(
213+
walletItems[2].querySelector('.ant-web3-connect-modal-icon > img')?.getAttribute('src'),
214+
).toBe(target2.icon);
215+
const groupTitle = baseElement.querySelectorAll('.ant-web3-connect-modal-group-title');
216+
expect(groupTitle[0]?.textContent).toBe('Popular');
217+
expect(groupTitle[1]?.textContent).toBe('More');
218+
});
219+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { ConnectButton, Connector } from '@ant-design/web3';
2+
import { ChromeCircleColorful } from '@ant-design/web3-icons';
3+
import { UniversalWallet, WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi';
4+
import { fireEvent, render } from '@testing-library/react';
5+
import { describe, expect, it, vi } from 'vitest';
6+
import { createConfig, http } from 'wagmi';
7+
import { mainnet } from 'wagmi/chains';
8+
import { injected } from 'wagmi/connectors';
9+
10+
const mockConnectAsync = vi.fn();
11+
12+
describe('WagmiWeb3ConfigProvider with EIP6963 Wallet', () => {
13+
it('Should correctly show all wallets discovered via EIP6963', () => {
14+
const target1 = {
15+
icon: 'icon1',
16+
id: 'com.mock.wallet1',
17+
name: 'mockWallet1',
18+
provider: undefined as any,
19+
};
20+
21+
const target2 = {
22+
icon: 'icon2',
23+
id: 'com.mock.wallet2',
24+
name: 'mockWallet2',
25+
provider: undefined as any,
26+
};
27+
28+
const mockDiscoveredConnectorsViaEIP6963 = [
29+
injected({
30+
target: target1,
31+
}),
32+
injected({
33+
target: target2,
34+
}),
35+
];
36+
37+
const config = createConfig({
38+
chains: [mainnet],
39+
transports: {
40+
[mainnet.id]: http(),
41+
},
42+
connectors: mockDiscoveredConnectorsViaEIP6963,
43+
});
44+
45+
const App = () => (
46+
<WagmiWeb3ConfigProvider
47+
eip6963={{
48+
autoAddInjectedWallets: true,
49+
}}
50+
config={config}
51+
>
52+
<Connector>
53+
<ConnectButton />
54+
</Connector>
55+
</WagmiWeb3ConfigProvider>
56+
);
57+
const { baseElement } = render(<App />);
58+
const btn = baseElement.querySelector('.ant-web3-connect-button');
59+
fireEvent.click(btn!);
60+
const walletItems = baseElement.querySelectorAll('.ant-web3-connect-modal-wallet-item');
61+
expect(walletItems.length).toBe(mockDiscoveredConnectorsViaEIP6963.length);
62+
expect(walletItems[0].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
63+
target1.name,
64+
);
65+
expect(walletItems[1].querySelector('.ant-web3-connect-modal-name')?.textContent).toBe(
66+
target2.name,
67+
);
68+
expect(
69+
walletItems[0].querySelector('.ant-web3-connect-modal-icon > img')?.getAttribute('src'),
70+
).toBe(target1.icon);
71+
expect(
72+
walletItems[1].querySelector('.ant-web3-connect-modal-icon > img')?.getAttribute('src'),
73+
).toBe(target2.icon);
74+
const groupTitle = baseElement.querySelector('.ant-web3-connect-modal-group-title');
75+
expect(groupTitle?.textContent).toBe('More');
76+
});
77+
78+
it('Should correctly connect the selected wallet', async () => {
79+
vi.mock('wagmi', async () => {
80+
const actual = await vi.importActual('wagmi');
81+
return {
82+
...actual,
83+
useConnect: () => {
84+
return {
85+
connectAsync: async (...args: any[]) => {
86+
mockConnectAsync(...args);
87+
},
88+
};
89+
},
90+
};
91+
});
92+
const target = {
93+
icon: 'icon1',
94+
id: 'com.mock.wallet1',
95+
name: 'mockWallet1',
96+
provider: {
97+
request: () => {},
98+
on: () => {},
99+
} as any,
100+
};
101+
102+
const mockDiscoveredConnectorsViaEIP6963 = [
103+
injected({
104+
target,
105+
}),
106+
];
107+
108+
const config = createConfig({
109+
chains: [mainnet],
110+
transports: {
111+
[mainnet.id]: http(),
112+
},
113+
connectors: mockDiscoveredConnectorsViaEIP6963,
114+
});
115+
116+
const App = () => (
117+
<WagmiWeb3ConfigProvider
118+
eip6963={{
119+
autoAddInjectedWallets: true,
120+
}}
121+
config={config}
122+
>
123+
<Connector>
124+
<ConnectButton />
125+
</Connector>
126+
</WagmiWeb3ConfigProvider>
127+
);
128+
const { baseElement } = render(<App />);
129+
const btn = baseElement.querySelector('.ant-web3-connect-button');
130+
fireEvent.click(btn!);
131+
const walletItem = baseElement.querySelector('.ant-web3-connect-modal-wallet-item');
132+
fireEvent.click(walletItem!);
133+
await vi.waitFor(() => {
134+
expect(mockConnectAsync).toHaveBeenCalledWith({
135+
connector: config.connectors[0],
136+
chainId: config.chains[0].id,
137+
});
138+
});
139+
});
140+
});

0 commit comments

Comments
 (0)