Skip to content

Commit b802b5d

Browse files
yutingzhao1991yutingzhao1991
and
yutingzhao1991
authored
feat: init @ant-design/web3-wagmi (#83)
* feat: init @ant-design/web3-wagmi * feat: init WagmiWeb3ConfigProvider demo and doc * chore: update module type * fix: rename eslintrc.js to eslintrc.cjs for fix test error * chore: config jsMinifierOptions for fix dumi build * feat: refact wallets in @ant-design/web3-ethereum and support accounts and wallets in @ant-design/web3-wagmi * feat: init getNFTMetadata in wagmi provider * fix: use bigint for tokenId for fix ci * feat: support showQrCode with WalletConnect * fix: use bigint for fix ci * fix: update tsconfig for fix eslint ci bug * test: add a simple test case for WagmiWeb3ConfigProvider * feat: NFTImage support use number as tokenId * feat: wrap WagmiConfig in WagmiWeb3ConfigProvider * fix: metamask install judge * choreL move wagmi/core dep to devDep * docs: update WagmiWeb3ConfigProvider usage --------- Co-authored-by: yutingzhao1991 <[email protected]>
1 parent db5211b commit b802b5d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1670
-442
lines changed

.dumi/tsconfig.json

-10
This file was deleted.

.dumirc.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@ export default defineConfig({
1010
},
1111
],
1212
},
13+
jsMinifierOptions: {
14+
target: ['chrome80', 'es2020'],
15+
},
1316
copy: ['CNAME'],
1417
define: {
1518
YOUR_ZAN_API_KEY: 'd0eeefc2a4da4a8ba707889259b437d6',
19+
YOUR_INFURA_API_KEY: '287294cbc30b44efab9455664b69b130',
1620
YOUR_WALLET_CONNET_PROJECT_ID: 'c07c0051c2055890eade3556618e38a6',
1721
},
1822
publicPath: process.env.PUBLIC_PATH || '/',

.eslintignore

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ dist
44
lib
55
es
66

7-
# 只检查 ts 文件
8-
**/*.js
9-
vitest.config.mts
7+
.umi-production
8+
.umi-test
9+
.umi

docs/guide/wagmi.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
nav: Guide
3+
group: Advance
4+
---
5+
6+
# Using with wagmi
7+
8+
<!-- prettier-ignore -->
9+
:::warning
10+
Waiting for translation
11+
:::

docs/guide/wagmi.zh-CN.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
nav: 指南
3+
group: 高级
4+
---
5+
6+
# 和 wagmi 一起使用
7+
8+
你可以通过我们提供的 `@ant-design/web3-wagmi` 简单便捷地和 [wagmi](https://wagmi.sh/) 一起使用。wagmi 是一个面向以太坊的 React Hooks 库,它不提供 UI,Ant Design Web3 可以作为它的一个很好的补充。
9+
10+
另外通过 `@ant-design/web3-wagmi`,Ant Design Web3 的组件可以基于 wagmi 提供的 Hooks 更加便捷可靠地连接到区块链,使用的示例如下:
11+
12+
```tsx | pure
13+
import { WagmiConfig, createConfig, configureChains, mainnet } from 'wagmi';
14+
import { publicProvider } from 'wagmi/providers/public';
15+
import { WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi';
16+
import { NFTImage } from '@ant-design/web3';
17+
18+
const { chains, publicClient } = configureChains([mainnet], [publicProvider()]);
19+
20+
const config = createConfig({
21+
autoConnect: true,
22+
publicClient,
23+
});
24+
25+
function App() {
26+
return (
27+
<WagmiWeb3ConfigProvider config={config}>
28+
<NFTImage address="0x79fcdef22feed20eddacbb2587640e45491b757f" tokenId={42} />
29+
</WagmiWeb3ConfigProvider>
30+
);
31+
}
32+
```
33+
34+
除了需要引入 `WagmiWeb3ConfigProvider` 替代 `WagmiConfig` 外,你完全不需要改变 wagmi 的任何用法。
35+
36+
## 使用示例
37+
38+
<code src="../../packages/web3/src/connect-button/demos/wagmi.tsx"></code>

package.json

+8-4
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"test:coverage": "vitest --coverage",
2424
"test:ci": "vitest --coverage",
2525
"lint": "pnpm run \"/^lint:.+/\"",
26-
"lint:eslint": "eslint --quiet --fix --ext .ts,.js .",
26+
"lint:eslint": "eslint --ext .ts,.tsx .",
2727
"lint:prettier": "prettier --loglevel warn --write '**/*.{ts,tsx,js,jsx,json,md}'",
2828
"lint:ts": "tsc --noEmit",
2929
"clean": "pnpm run \"/^clean:.+/\"",
@@ -39,17 +39,20 @@
3939
"*.{json,less,md}": "prettier --ignore-unknown --write"
4040
},
4141
"devDependencies": {
42+
"@ant-design/web3": "workspace:*",
43+
"@ant-design/web3-ethereum": "workspace:*",
44+
"@ant-design/web3-wagmi": "workspace:*",
45+
"@biomejs/biome": "^1.0.0",
4246
"@changesets/changelog-git": "^0.1.14",
4347
"@changesets/cli": "^2.26.2",
4448
"@testing-library/react": "^14.0.0",
45-
"@biomejs/biome": "^1.0.0",
4649
"@types/node": "^16.6.1",
4750
"@types/react": "^18.2.20",
4851
"@umijs/fabric": "^2.14.1",
4952
"@vitest/coverage-v8": "^0.34.6",
5053
"antd": "^5.8.3",
5154
"dumi": "^2.2.6",
52-
"eslint": "^7.32.0",
55+
"eslint": "^8.53.0",
5356
"ethers": "^6.7.1",
5457
"father": "^4.1.9",
5558
"husky": "^8.0.3",
@@ -60,7 +63,8 @@
6063
"react-dom": "^18.2.0",
6164
"rimraf": "^5.0.0",
6265
"typescript": "^5.0.4",
63-
"vitest": "^0.34.6"
66+
"vitest": "^0.34.6",
67+
"wagmi": "^1.4.5"
6468
},
6569
"ci": {
6670
"type": "aci",

packages/common/package.json

+1-5
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,5 @@
4040
"Firefox ESR",
4141
"> 1%",
4242
"ie >= 11"
43-
],
44-
"dependencies": {
45-
"@walletconnect/ethereum-provider": "^2.10.2",
46-
"@walletconnect/modal": "^2.6.2"
47-
}
43+
]
4844
}

packages/common/src/index.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export * from './types';
2-
export * from './wallets/index';
3-
export * from './rpc-providers';
42
export * from './utils';
53
export * from './web3-config-provider';
4+
export * from './wallets';
65

76
export * as chains from './chains';

packages/common/src/types.ts

+2-39
Original file line numberDiff line numberDiff line change
@@ -40,54 +40,17 @@ export interface UniversalWeb3ProviderInterface {
4040
requestAccounts?: (wallet?: string) => Promise<Account[]>;
4141
disconnect?: () => Promise<void>;
4242

43-
getAccounts?: () => Promise<Account[]>;
44-
getCurrentAccount?: () => Promise<Account | undefined>;
4543
getCurrentNetwork?: () => Promise<number>;
46-
getNFTMetadata?: (params: { address: string; tokenId: number }) => Promise<NFTMetadata>;
47-
getAvaliableWallets?: () => Promise<Wallet[]>;
44+
getNFTMetadata?: (params: { address: string; tokenId: bigint }) => Promise<NFTMetadata>;
4845
}
4946

50-
/**
51-
* This interface is a subset of the EIP-1193 provider interface.
52-
* See: https://eips.ethereum.org/EIPS/eip-1193
53-
*/
54-
export interface EIP1193LikeProvider {
55-
request: (request: { method: string; params?: any }) => Promise<any>;
56-
// connect and disconnect for WallectConnect
57-
connect?: () => Promise<void>;
58-
disconnect?: () => Promise<void>;
59-
networkVersion?: string;
60-
}
61-
62-
export interface WalletProviderOptions {
63-
chains?: Chain[];
64-
}
65-
66-
export interface Wallet extends WalletMetadata, EIP1193IncludeProvider {
67-
provider?: EIP1193LikeProvider;
47+
export interface Wallet extends WalletMetadata {
6848
hasBrowserExtensionInstalled?: () => Promise<boolean>;
6949
getQrCode?: () => Promise<{
7050
uri: string;
7151
}>;
7252
}
7353

74-
export interface EIP1193IncludeProvider {
75-
provider?: EIP1193LikeProvider;
76-
}
77-
78-
export interface EIP1193IncludeProviderFactory {
79-
create: (options?: WalletProviderOptions) => Promise<EIP1193IncludeProvider>;
80-
}
81-
82-
export interface WalletProvider extends EIP1193IncludeProviderFactory {
83-
metadata: WalletMetadata;
84-
create: (options?: WalletProviderOptions) => Promise<Wallet>;
85-
}
86-
87-
export interface JsonRpcProvider extends EIP1193IncludeProviderFactory {
88-
getRpcUrl: (chain: Chain) => string;
89-
}
90-
9154
/**
9255
* @desc 浏览器扩展程序信息
9356
*/
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { fillAddressWith0x, parseNumberToBigint } from './format';
3+
4+
describe('utils.format', () => {
5+
it('should fill address with 0x', () => {
6+
expect(fillAddressWith0x('0x123')).toBe('0x123');
7+
expect(fillAddressWith0x('123')).toBe('0x123');
8+
});
9+
10+
it('should parse number to bigint', () => {
11+
expect(parseNumberToBigint(123)).toBe(123n);
12+
expect(parseNumberToBigint(123n)).toBe(123n);
13+
});
14+
});

packages/common/src/utils/format.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function fillAddressWith0x(address: string): `0x${string}` {
2+
return (address.startsWith('0x') ? address : `0x${address}`) as `0x${string}`;
3+
}
4+
5+
export function parseNumberToBigint(num: number | bigint) {
6+
return typeof num !== 'bigint' ? BigInt(num) : num;
7+
}

packages/common/src/utils/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './request';
2+
export * from './format';
+18-34
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,20 @@
1-
import { WalletMetadata, Wallet, WalletProvider } from '../types';
1+
import { WalletMetadata } from '../types';
22

3-
export class MetaMaskProvider implements WalletProvider {
4-
metadata: WalletMetadata = {
5-
icon: 'https://metamask.io/images/metamask-logo.png',
6-
name: 'MetaMask',
7-
remark: 'MetaMask Wallet',
8-
app: {
9-
link: 'https://metamask.io/',
3+
export const metadata_MetaMask: WalletMetadata = {
4+
icon: 'https://metamask.io/images/metamask-logo.png',
5+
name: 'MetaMask',
6+
remark: 'MetaMask Wallet',
7+
app: {
8+
link: 'https://metamask.io/',
9+
},
10+
extensions: [
11+
{
12+
key: 'Chrome',
13+
browserIcon:
14+
'https://github.com/ant-design/ant-design/assets/10286961/0d4e4ac7-8f89-4147-a06a-de72c02e85cb',
15+
browserName: 'Chrome',
16+
link: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
17+
description: 'Access your wallet right from your favorite web browser.',
1018
},
11-
extensions: [
12-
{
13-
key: 'Chrome',
14-
browserIcon:
15-
'https://github.com/ant-design/ant-design/assets/10286961/0d4e4ac7-8f89-4147-a06a-de72c02e85cb',
16-
browserName: 'Chrome',
17-
link: 'https://chrome.google.com/webstore/detail/metamask/nkbihfbeogaeaoehlefnkodbefgpgknn',
18-
description: 'Access your wallet right from your favorite web browser.',
19-
},
20-
],
21-
};
22-
23-
create = async (): Promise<Wallet> => {
24-
if (!window.ethereum) {
25-
throw new Error('MetaMask is not installed');
26-
}
27-
return {
28-
provider: window.ethereum,
29-
...this.metadata,
30-
};
31-
};
32-
33-
hasBrowserExtensionInstalled = async (): Promise<boolean> => {
34-
return window.ethereum && window.ethereum?.isMetaMask ? true : false;
35-
};
36-
}
19+
],
20+
};
+11-80
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,11 @@
1-
// Only for WallectConnect v2, v1 is not supported
2-
import { Wallet, WalletMetadata, WalletProvider, WalletProviderOptions } from '../types';
3-
import { EthereumProvider } from '@walletconnect/ethereum-provider';
4-
5-
export interface WalletConnectConfig {
6-
projectId: string;
7-
showQrModal?: boolean;
8-
}
9-
10-
export class WalletConnectProvider implements WalletProvider {
11-
metadata: WalletMetadata = {
12-
icon: 'https://docs.walletconnect.com/img/walletconnect-logo-black.svg#light-mode-only',
13-
name: 'WalletConnect',
14-
remark: 'Connect with mobile APP',
15-
app: {
16-
link: 'https://walletconnect.com/',
17-
},
18-
group: 'Popular',
19-
};
20-
21-
private qrCodeLinkPromise: Promise<string> | undefined;
22-
private resolveQrCodeLink: ((uri: string) => void) | undefined;
23-
24-
constructor(private config?: WalletConnectConfig) {}
25-
26-
create = async (options?: WalletProviderOptions): Promise<Wallet> => {
27-
const { projectId, showQrModal = false } = this.config || {};
28-
if (!projectId) {
29-
throw new Error('walletConnectProjectId is required');
30-
}
31-
let chains = [1];
32-
if (options?.chains && options?.chains?.length > 0) {
33-
chains = options.chains.map((chain) => chain.id as number);
34-
}
35-
// docs: https://docs.walletconnect.com/advanced/providers/ethereum
36-
const provider = await EthereumProvider.init({
37-
projectId: projectId,
38-
chains: [chains[0]],
39-
optionalChains: chains,
40-
showQrModal,
41-
methods: ['eth_requestAccounts', 'eth_accounts'],
42-
events: [],
43-
});
44-
45-
provider.on('display_uri', (uri: string) => {
46-
this.resolveQrCodeLink?.(uri);
47-
});
48-
49-
provider.on('disconnect', () => {
50-
this.initQrCodePromise();
51-
});
52-
53-
this.initQrCodePromise();
54-
55-
return {
56-
provider,
57-
...this.metadata,
58-
getQrCode: async () => {
59-
if (!this.qrCodeLinkPromise) {
60-
throw new Error('WalletConnect is not initialized');
61-
}
62-
const uri = await this.qrCodeLinkPromise;
63-
return {
64-
uri,
65-
};
66-
},
67-
};
68-
};
69-
70-
hasBrowserExtensionInstalled = async (): Promise<boolean> => {
71-
// If showQrModal is true, it means use WalletConnet offcial modal, Think it's the same as installing extension
72-
return this.config?.showQrModal ?? false;
73-
};
74-
75-
private initQrCodePromise = () => {
76-
this.qrCodeLinkPromise = new Promise((resolve) => {
77-
this.resolveQrCodeLink = resolve;
78-
});
79-
};
80-
}
1+
import { WalletMetadata } from '../types';
2+
3+
export const metadata_WalletConnect: WalletMetadata = {
4+
icon: 'https://docs.walletconnect.com/img/walletconnect-logo-black.svg#light-mode-only',
5+
name: 'WalletConnect',
6+
remark: 'Connect with mobile APP',
7+
app: {
8+
link: 'https://walletconnect.com/',
9+
},
10+
group: 'Popular',
11+
};

packages/common/tsconfig.json

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
{
22
"extends": "../../tsconfig.base.json",
3-
"compilerOptions": {
4-
"baseUrl": "."
5-
},
6-
"include": ["src", "global.d.ts"]
3+
"include": ["src", "global.d.ts", "../ethereum/src/wallets"]
74
}

packages/ethereum/package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
"dependencies": {
2222
"@ant-design/web3-common": "workspace:*",
2323
"debug": "^4.3.4",
24-
"eventemitter3": "^5.0.1"
24+
"eventemitter3": "^5.0.1",
25+
"@walletconnect/ethereum-provider": "^2.10.2",
26+
"@walletconnect/modal": "^2.6.2"
2527
},
2628
"devDependencies": {
2729
"@types/debug": "^4.1.9",

0 commit comments

Comments
 (0)