Skip to content

Commit

Permalink
feat: wagmi provider support ENS (#101)
Browse files Browse the repository at this point in the history
Co-authored-by: yutingzhao1991 <[email protected]>
  • Loading branch information
yutingzhao1991 and yutingzhao1991 authored Nov 21, 2023
1 parent 89c6077 commit 86ab2eb
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 45 deletions.
3 changes: 2 additions & 1 deletion packages/common/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export interface Account {
address: string;
name?: string;
}

export enum ChainIds {
Expand Down Expand Up @@ -145,7 +146,7 @@ export interface ConnectorTriggerProps {
onConnectClick?: () => void;
onDisconnectClick?: () => Promise<void>;
onSwitchChain?: (chain: Chain) => Promise<void>;
domain?: string;
name?: string;
connected?: boolean;
chains?: Chain[];
currentChain?: Chain;
Expand Down
66 changes: 23 additions & 43 deletions packages/wagmi/src/wagmi-provider/config-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import React from 'react';
import {
type Account,
type Wallet,
type Chain,
Web3ConfigProvider,
requestWeb3Asset,
fillAddressWith0x,
} from '@ant-design/web3-common';
import { type Account, type Wallet, type Chain, Web3ConfigProvider } from '@ant-design/web3-common';
import {
useAccount,
useConnect,
Expand All @@ -15,34 +8,41 @@ import {
useSwitchNetwork,
type Chain as WagmiChain,
} from 'wagmi';
import { readContract } from '@wagmi/core';
import { addNameToAccounts, getNFTMetadata } from './methods';
import type { WalletFactory } from '../interface';

export interface AntDesignWeb3ConfigProviderProps {
assets?: (WalletFactory | Chain)[];
children?: React.ReactNode;
ens?: boolean;
chains: WagmiChain[];
}

export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderProps> = (props) => {
const { children, assets, chains } = props;
const { children, assets, chains, ens } = props;
const { address, isDisconnected } = useAccount();
const [accounts, setAccounts] = React.useState<Account[]>([]);
const { connectors, connectAsync } = useConnect();
const { switchNetwork } = useSwitchNetwork();
const { chain } = useNetwork();
const { disconnectAsync } = useDisconnect();
const [currentChain, setCurrentChain] = React.useState<Chain | undefined>(undefined);

const accounts: Account[] = React.useMemo(() => {
React.useEffect(() => {
if (!address || isDisconnected) {
return [];
setAccounts([]);
return;
}
return [
{
address,
},
];
}, [address, isDisconnected]);
const updateAccounts = async () => {
const as: Account[] = [
{
address,
},
];
setAccounts(ens ? await addNameToAccounts(as) : as);
};
updateAccounts();
}, [address, isDisconnected, chain, ens]);

const wallets: Wallet[] = React.useMemo(() => {
return connectors.map((connector) => {
Expand Down Expand Up @@ -103,42 +103,22 @@ export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderPr
connector,
chainId: currentChain?.id,
});
return [
const as = [
{
address: account,
},
];
return ens ? addNameToAccounts(as, chain?.id) : as;
}}
disconnect={async () => {
await disconnectAsync();
}}
switchChain={async (c: Chain) => {
switchNetwork?.(c.id);
}}
getNFTMetadata={async ({ address: contractAddress, tokenId }) => {
const tokenURI = await readContract({
address: fillAddressWith0x(contractAddress),
args: [tokenId],
chainId: chain?.id,
abi: [
{
name: 'tokenURI',
inputs: [
{
name: 'tokenId',
type: 'uint256',
},
],
outputs: [{ name: '', type: 'string' }],
stateMutability: 'view',
type: 'function',
},
],
functionName: 'tokenURI',
});
const metaInfo = await requestWeb3Asset(tokenURI as string);
return metaInfo;
}}
getNFTMetadata={async ({ address: contractAddress, tokenId }) =>
getNFTMetadata(contractAddress, tokenId, chain?.id)
}
>
{children}
</Web3ConfigProvider>
Expand Down
3 changes: 3 additions & 0 deletions packages/wagmi/src/wagmi-provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type WagmiWeb3ConfigProviderProps<
config: Config<TPublicClient, TWebSocketPublicClient>;
chains?: WagmiChain[];
assets?: (Chain | WalletFactory)[];
ens?: boolean;
};

export function WagmiWeb3ConfigProvider<
Expand All @@ -25,6 +26,7 @@ export function WagmiWeb3ConfigProvider<
children,
assets = [],
chains = [mainnet],
ens,
...restProps
}: React.PropsWithChildren<
WagmiWeb3ConfigProviderProps<TPublicClient, TWebSocketPublicClient>
Expand All @@ -34,6 +36,7 @@ export function WagmiWeb3ConfigProvider<
<AntDesignWeb3ConfigProvider
assets={[...assets, MetaMask, WallectConnect, Mainnet, Polygon, BSC, Goerli]}
chains={chains}
ens={ens}
>
{children}
</AntDesignWeb3ConfigProvider>
Expand Down
17 changes: 17 additions & 0 deletions packages/wagmi/src/wagmi-provider/methods/addNameToAccounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Account } from '@ant-design/web3-common';
import { fetchEnsName } from '@wagmi/core';

export async function addNameToAccounts(accounts: Account[], chainId?: number): Promise<Account[]> {
return Promise.all(
accounts.map(async (account) => {
const name = await fetchEnsName({
address: account.address as `0x${string}`,
chainId,
});
return {
...account,
name: name ?? undefined,
};
}),
);
}
31 changes: 31 additions & 0 deletions packages/wagmi/src/wagmi-provider/methods/getNFTMetadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { requestWeb3Asset, fillAddressWith0x, type NFTMetadata } from '@ant-design/web3-common';
import { readContract } from '@wagmi/core';

export async function getNFTMetadata(
address: string,
tokenId: bigint,
chainId?: number,
): Promise<NFTMetadata> {
const tokenURI = await readContract({
address: fillAddressWith0x(address),
args: [tokenId],
chainId,
abi: [
{
name: 'tokenURI',
inputs: [
{
name: 'tokenId',
type: 'uint256',
},
],
outputs: [{ name: '', type: 'string' }],
stateMutability: 'view',
type: 'function',
},
],
functionName: 'tokenURI',
});
const metaInfo = await requestWeb3Asset(tokenURI as string);
return metaInfo;
}
35 changes: 35 additions & 0 deletions packages/wagmi/src/wagmi-provider/methods/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { addNameToAccounts } from './index';
import { vi, describe, it, expect } from 'vitest';

vi.mock('@wagmi/core', () => {
return {
fetchEnsName: ({ address }: { address: string }) => {
if (address === '0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B') {
return 'wanderingearth,eth';
}
return null;
},
};
});

describe('wagmi-provider/methods/index.ts', () => {
it('addNameToAccounts', async () => {
const accounts = await addNameToAccounts([
{
address: '0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B',
},
{
address: '0x21CDf0974d53a6e96eF05d7B324a9803735f0000',
},
]);
expect(accounts).toEqual([
{
address: '0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B',
name: 'wanderingearth,eth',
},
{
address: '0x21CDf0974d53a6e96eF05d7B324a9803735f0000',
},
]);
});
});
2 changes: 2 additions & 0 deletions packages/wagmi/src/wagmi-provider/methods/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './addNameToAccounts';
export * from './getNFTMetadata';
42 changes: 42 additions & 0 deletions packages/web3/src/connector/__tests__/name.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Connector, type ConnectorTriggerProps, type Account } from '@ant-design/web3';
import React from 'react';
import { Button } from 'antd';
import { render } from '@testing-library/react';
import { it, describe, expect } from 'vitest';

describe('Connector', () => {
it('name', async () => {
const CustomButton: React.FC<React.PropsWithChildren<ConnectorTriggerProps>> = (props) => {
const { name, address, connected, onConnectClick, onDisconnectClick, children } = props;
return (
<Button
onClick={() => {
if (connected) {
onDisconnectClick?.();
} else {
onConnectClick?.();
}
}}
>
{(name || address) ?? children}
</Button>
);
};

const App = () => {
const [accounts] = React.useState<Account[]>([
{
address: '0x1234567890',
name: 'wanderingearth.eth',
},
]);
return (
<Connector accounts={accounts}>
<CustomButton>children</CustomButton>
</Connector>
);
};
const { baseElement } = render(<App />);
expect(baseElement.querySelector('.ant-btn')?.textContent).toBe('wanderingearth.eth');
});
});
1 change: 1 addition & 0 deletions packages/web3/src/connector/conector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const Connector: React.FC<ConnectorProps> = (props) => {
{contextHolder}
{React.cloneElement(children as React.ReactElement<ConnectorTriggerProps>, {
address: currentAccount?.address,
name: currentAccount?.name,
connected: !!currentAccount,
loading,
onConnectClick: () => {
Expand Down
37 changes: 37 additions & 0 deletions packages/web3/src/connector/demos/name.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createConfig, configureChains, mainnet } from 'wagmi';
import { publicProvider } from 'wagmi/providers/public';
import { MetaMaskConnector } from 'wagmi/connectors/metaMask';
import { WalletConnectConnector } from 'wagmi/connectors/walletConnect';
import { WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi';
import { ConnectButton, Connector } from '@ant-design/web3';

const { publicClient, chains } = configureChains([mainnet], [publicProvider()]);

const config = createConfig({
autoConnect: true,
publicClient,
connectors: [
new MetaMaskConnector({
chains,
}),
new WalletConnectConnector({
chains,
options: {
showQrModal: false,
projectId: YOUR_WALLET_CONNET_PROJECT_ID,
},
}),
],
});

const App: React.FC = () => {
return (
<WagmiWeb3ConfigProvider ens config={config}>
<Connector>
<ConnectButton />
</Connector>
</WagmiWeb3ConfigProvider>
);
};

export default App;
4 changes: 4 additions & 0 deletions packages/web3/src/connector/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ group: Components

<code src="./demos/chains.tsx"></code>

## Display ENS

<code src="./demos/name.tsx"></code>

## Use web3modal for WallectConnect

<code src="./demos/web3modal.tsx"></code>
Expand Down
6 changes: 5 additions & 1 deletion packages/web3/src/connector/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ group: 组件

<code src="./demos/chains.tsx"></code>

## 显示 ENS

<code src="./demos/name.tsx"></code>

## 使用 web3modal 连接 WallectConnect

<code src="./demos/web3modal.tsx"></code>
Expand Down Expand Up @@ -51,7 +55,7 @@ group: 组件
| onConnectClick | 连接事件 | `React.MouseEventHandler` | - | - |
| onDisconnectClick | 断开连接事件 | `React.MouseEventHandler` | - | - |
| onSwitchChain | 切换网络事件 | `(chain: Chain) => Promise<viod>` | - | - |
| domain | address 对应的域名,通常就是指 ENS | `string` | - | - |
| name | address 对应的名称,通常就是指 ENS | `string` | - | - |
| connected | 是否已连接 | `boolean` | - | - |
| chains | 当前连接的网络列表 | `ChainSelectItem[]` | - | - |
| banlance | 当前连接的账户余额 | `Banlance[]` \| `Banlance` | - | - |

0 comments on commit 86ab2eb

Please sign in to comment.