From 4abe7c0e6ba7f39b86e43d69e767a856f9171e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=84=9A=E6=8C=87=E5=AF=BC?= Date: Wed, 12 Jun 2024 17:20:30 +0800 Subject: [PATCH] feat: onConnected callback support provider account (#933) * feat: onConnected callback support provider account * chore: add changelog * fix: test * chore: update demo * test: improve test coverage * fix: eslint issue --------- Co-authored-by: tingzhao.ytz Co-authored-by: thinkasany <480968828@qq.com> --- .changeset/serious-ducks-jog.md | 7 ++ packages/common/src/types.ts | 2 +- .../config-with-eip6963-and-wallets.test.tsx | 1 + .../config-with-eip6963-wallet.test.tsx | 1 + .../connect-with-universal-wallet.test.tsx | 1 + .../wagmi-provider/__tests__/connect.test.tsx | 18 ++++- .../src/wagmi-provider/__tests__/ens.test.tsx | 4 +- .../src/wagmi-provider/__tests__/nft.test.tsx | 4 +- .../__tests__/unconnected.test.tsx | 4 +- .../src/wagmi-provider/config-provider.tsx | 5 +- .../src/connector/__tests__/basic.test.tsx | 80 ++++++++++++++++++- packages/web3/src/connector/connector.tsx | 4 +- packages/web3/src/connector/index.md | 10 +-- packages/web3/src/connector/index.zh-CN.md | 10 +-- packages/web3/src/connector/interface.ts | 4 +- packages/web3/src/ethereum/demos/eip6963.tsx | 9 ++- packages/web3/src/types/index.md | 2 +- packages/web3/src/types/index.zh-CN.md | 2 +- 18 files changed, 139 insertions(+), 29 deletions(-) create mode 100644 .changeset/serious-ducks-jog.md diff --git a/.changeset/serious-ducks-jog.md b/.changeset/serious-ducks-jog.md new file mode 100644 index 000000000..02adf9cb6 --- /dev/null +++ b/.changeset/serious-ducks-jog.md @@ -0,0 +1,7 @@ +--- +'@ant-design/web3-common': minor +'@ant-design/web3-wagmi': minor +'@ant-design/web3': minor +--- + +feat: onConnected callback support provider account diff --git a/packages/common/src/types.ts b/packages/common/src/types.ts index d0d62aea6..480c872b1 100644 --- a/packages/common/src/types.ts +++ b/packages/common/src/types.ts @@ -99,7 +99,7 @@ export interface UniversalWeb3ProviderInterface { /** Such as `0x` */ addressPrefix?: string | false; - connect?: (wallet?: Wallet, options?: ConnectOptions) => Promise; + connect?: (wallet?: Wallet, options?: ConnectOptions) => Promise; disconnect?: () => Promise; switchChain?: (chain: Chain) => Promise; diff --git a/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-and-wallets.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-and-wallets.test.tsx index 385b27ca9..cde740130 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-and-wallets.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-and-wallets.test.tsx @@ -17,6 +17,7 @@ vi.mock('wagmi', async () => { return { connectAsync: async (...args: any[]) => { mockConnectAsync(...args); + return {}; }, }; }, diff --git a/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-wallet.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-wallet.test.tsx index 6d869dbf6..cf33fd9fb 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-wallet.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/config-with-eip6963-wallet.test.tsx @@ -83,6 +83,7 @@ describe('WagmiWeb3ConfigProvider with EIP6963 Wallet', () => { return { connectAsync: async (...args: any[]) => { mockConnectAsync(...args); + return {}; }, }; }, diff --git a/packages/wagmi/src/wagmi-provider/__tests__/connect-with-universal-wallet.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/connect-with-universal-wallet.test.tsx index 249f977bb..eb1e22dd4 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/connect-with-universal-wallet.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/connect-with-universal-wallet.test.tsx @@ -58,6 +58,7 @@ vi.mock('wagmi', () => { connectAsync: (options: any) => { connectAsync(options); event.emit('connectChanged', true); + return {}; }, }; }, diff --git a/packages/wagmi/src/wagmi-provider/__tests__/connect.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/connect.test.tsx index cb1d239d6..b2788bb8a 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/connect.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/connect.test.tsx @@ -50,9 +50,15 @@ vi.mock('wagmi', () => { useConnect: () => { return { connectors: [mockConnector], - connectAsync: () => { + connectAsync: async () => { connectAsync(); event.emit('connectChanged', true); + return { + accounts: [ + '0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B', + '0x0212f0974d53a6e96eF05d7B324a9803735fFd3B', + ], + }; }, }; }, @@ -78,18 +84,20 @@ vi.mock('wagmi', () => { describe('WagmiWeb3ConfigProvider connect', () => { it('connect', async () => { + const onConnected = vi.fn(); const CustomConnector = () => { const { connect, account, disconnect } = useProvider(); return (
{ + onClick={async () => { if (account) { disconnect?.(); return; } - connect?.(MetaMask().create([mockConnector])); + const res = await connect?.(MetaMask().create([mockConnector])); + onConnected(res); }} > {account ? account?.address : 'Connect'} @@ -119,6 +127,10 @@ describe('WagmiWeb3ConfigProvider connect', () => { ); }); + expect(onConnected).toBeCalledWith({ + address: '0x21CDf0974d53a6e96eF05d7B324a9803735fFd3B', + }); + fireEvent.click(baseElement.querySelector('.custom-text')!); await vi.waitFor(() => { expect(disconnectAsync).toBeCalled(); diff --git a/packages/wagmi/src/wagmi-provider/__tests__/ens.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/ens.test.tsx index 44768b555..b59ca1c99 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/ens.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/ens.test.tsx @@ -30,7 +30,9 @@ vi.mock('wagmi', () => { useConnect: () => { return { connectors: [], - connectAsync: () => {}, + connectAsync: async () => { + return {}; + }, }; }, useDisconnect: () => { diff --git a/packages/wagmi/src/wagmi-provider/__tests__/nft.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/nft.test.tsx index be5c047b8..5f24271fe 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/nft.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/nft.test.tsx @@ -31,7 +31,9 @@ vi.mock('wagmi', () => { useConnect: () => { return { connectors: [], - connectAsync: () => {}, + connectAsync: async () => { + return {}; + }, }; }, useDisconnect: () => { diff --git a/packages/wagmi/src/wagmi-provider/__tests__/unconnected.test.tsx b/packages/wagmi/src/wagmi-provider/__tests__/unconnected.test.tsx index 87359a215..be420448d 100644 --- a/packages/wagmi/src/wagmi-provider/__tests__/unconnected.test.tsx +++ b/packages/wagmi/src/wagmi-provider/__tests__/unconnected.test.tsx @@ -31,7 +31,9 @@ vi.mock('wagmi', () => { useConnect: () => { return { connectors: [mockConnector], - connectAsync: () => {}, + connectAsync: async () => { + return {}; + }, }; }, useDisconnect: () => { diff --git a/packages/wagmi/src/wagmi-provider/config-provider.tsx b/packages/wagmi/src/wagmi-provider/config-provider.tsx index 32da849fb..1197bd58c 100644 --- a/packages/wagmi/src/wagmi-provider/config-provider.tsx +++ b/packages/wagmi/src/wagmi-provider/config-provider.tsx @@ -209,10 +209,13 @@ export const AntDesignWeb3ConfigProvider: React.FC { // await disconnectAsync(); diff --git a/packages/web3/src/connector/__tests__/basic.test.tsx b/packages/web3/src/connector/__tests__/basic.test.tsx index fc9d8f6b7..fe89f4271 100644 --- a/packages/web3/src/connector/__tests__/basic.test.tsx +++ b/packages/web3/src/connector/__tests__/basic.test.tsx @@ -116,7 +116,7 @@ describe('Connector', () => { ); }; - const onConnected = vi.fn(); + const onConnected = vi.fn((account) => account); const App = () => { const [account, setAccount] = React.useState(); @@ -136,14 +136,17 @@ describe('Connector', () => { setAccount({ address: '0x1234567890', }); + return { + address: '0x1234567890', + }; }} disconnect={async () => { setAccount(undefined); }} onDisconnected={onDisconnected} onDisconnect={onDisconnect} - onConnected={() => { - onConnected(); + onConnected={(a) => { + onConnected(a); }} > children @@ -161,7 +164,7 @@ describe('Connector', () => { await vi.waitFor(() => { expect(onConnectCallTest).toBeCalled(); - expect(onConnected).toBeCalled(); + expect(onConnected).toBeCalledWith({ address: '0x1234567890' }); }); fireEvent.click(baseElement.querySelector('.ant-modal-close')!); @@ -180,6 +183,75 @@ describe('Connector', () => { expect(baseElement.querySelector('.ant-btn')?.textContent).toBe('children'); }); + it('connect without return account info', async () => { + const onConnectCallTest = vi.fn(); + const onDisconnected = vi.fn(); + const onDisconnect = vi.fn(); + const CustomButton: React.FC> = (props) => { + const { account, onConnectClick, onDisconnectClick, children } = props; + return ( + + ); + }; + const onConnected = vi.fn((account) => account); + + const App = () => { + const [account, setAccount] = React.useState(); + return ( + { + return true; + }, + }, + ]} + onConnect={onConnectCallTest} + connect={async () => { + setAccount({ + address: '0x1234567890', + }); + }} + disconnect={async () => { + setAccount(undefined); + }} + onDisconnected={onDisconnected} + onDisconnect={onDisconnect} + onConnected={(a) => { + onConnected(a); + }} + > + children + + ); + }; + const { baseElement } = render(); + expect(baseElement.querySelector('.ant-btn')?.textContent).toBe('children'); + fireEvent.click(baseElement.querySelector('.ant-btn')!); + + await vi.waitFor(() => { + expect(baseElement.querySelector('.ant-web3-connect-modal-wallet-item')).toBeTruthy(); + }); + fireEvent.click(baseElement.querySelector('.ant-web3-connect-modal-wallet-item')!); + + await vi.waitFor(() => { + expect(onConnectCallTest).toBeCalled(); + expect(onConnected).toBeCalledWith(undefined); + }); + }); + it('should support controlled loading', async () => { const App = () => { const [account, setAccount] = React.useState(); diff --git a/packages/web3/src/connector/connector.tsx b/packages/web3/src/connector/connector.tsx index 69a04c152..323b68d6b 100644 --- a/packages/web3/src/connector/connector.tsx +++ b/packages/web3/src/connector/connector.tsx @@ -38,8 +38,8 @@ export const Connector: React.FC = (props) => { onConnect?.(); try { setConnecting(true); - await connect?.(wallet, options); - onConnected?.(); + const connectedAccount = await connect?.(wallet, options); + onConnected?.(connectedAccount ? connectedAccount : undefined); setOpen(false); } catch (e: any) { if (typeof onConnectError === 'function') { diff --git a/packages/web3/src/connector/index.md b/packages/web3/src/connector/index.md index 6f5b67497..3cb4c1188 100644 --- a/packages/web3/src/connector/index.md +++ b/packages/web3/src/connector/index.md @@ -29,11 +29,11 @@ In addition, `Connector` is usually used with [adapter](../../guide/adapter). Th | --- | --- | --- | --- | --- | | children | Connection control, typically a `ConnectButton` | `React.ReactNode` | - | - | | modalProps | Properties passed through to `ConnectModal`. | `ModalProps` | - | - | -| onConnect | Callback when triggering the connection. | `() => Promise` | - | - | -| onDisconnect | Callback when triggering the disconnection. | `() => Promise` | - | - | -| onConnected | Callback when the connection is successful. | `() => Promise` | - | - | -| onDisconnected | Callback when the connection is disconnected. | `() => Promise` | - | - | -| onChainSwitched | Callback when switching networks. | `(chain: Chain) => Promise` | - | - | +| onConnect | Callback when triggering the connection. | `() => void` | - | - | +| onDisconnect | Callback when triggering the disconnection. | `() => void` | - | - | +| onConnected | Callback when the connection is successful. The availability of `account` depends on the adapter implementation. | `(account?: Account) => void` | - | - | +| onDisconnected | Callback when the connection is disconnected. | `() => void` | - | - | +| onChainSwitched | Callback when switching networks. | `(chain: Chain) => void` | - | - | | availableWallets | Available aallet list | `Wallet[]` | - | - | | account | Current connected account | `Account` | - | - | | availableChains | List of available chains | `Chain[]` | - | - | diff --git a/packages/web3/src/connector/index.zh-CN.md b/packages/web3/src/connector/index.zh-CN.md index 6c7f649ce..e40981f9a 100644 --- a/packages/web3/src/connector/index.zh-CN.md +++ b/packages/web3/src/connector/index.zh-CN.md @@ -30,11 +30,11 @@ group: UI 组件 | --- | --- | --- | --- | --- | | children | 连接控件,通常是 `ConnectButton` | `React.ReactNode` | - | - | | modalProps | 透传给 `ConnectModal` 的属性 | `ModalProps` | - | - | -| onConnect | 触发连接时的回调 | `() => Promise` | - | - | -| onDisconnect | 触发断开连接时的回调 | `() => Promise` | - | - | -| onConnected | 连接成功时的回调 | `() => Promise` | - | - | -| onDisconnected | 断开连接时的回调 | `() => Promise` | - | - | -| onChainSwitched | 切换网络时的回调 | `(chain: Chain) => Promise` | - | - | +| onConnect | 触发连接时的回调 | `() => void` | - | - | +| onDisconnect | 触发断开连接时的回调 | `() => void` | - | - | +| onConnected | 连接成功时的回调,`account` 是否可用取决于适配器实现 | `(account?: Account) => void` | - | - | +| onDisconnected | 断开连接时的回调 | `() => void` | - | - | +| onChainSwitched | 切换网络时的回调 | `(chain: Chain) => void` | - | - | | availableWallets | 钱包列表 | `Wallet[]` | - | - | | account | 当前连接账号 | `Account[]` | - | - | | availableChains | 可以连接的链列表 | `Chain[]` | - | - | diff --git a/packages/web3/src/connector/interface.ts b/packages/web3/src/connector/interface.ts index bcf08a4a9..1500dcd5e 100644 --- a/packages/web3/src/connector/interface.ts +++ b/packages/web3/src/connector/interface.ts @@ -6,7 +6,7 @@ export interface ConnectorProps { modalProps?: ConnectModalProps; onConnect?: () => void; onDisconnect?: () => void; - onConnected?: () => void; + onConnected?: (account?: Account) => void; onDisconnected?: () => void; onChainSwitched?: (chain?: Chain) => void; onConnectError?: (error?: Error) => void; @@ -17,7 +17,7 @@ export interface ConnectorProps { availableChains?: Chain[]; availableWallets?: Wallet[]; - connect?: (wallet?: Wallet) => Promise; + connect?: (wallet?: Wallet) => Promise; disconnect?: () => Promise; switchChain?: (chain: Chain) => Promise; } diff --git a/packages/web3/src/ethereum/demos/eip6963.tsx b/packages/web3/src/ethereum/demos/eip6963.tsx index e7e067d6f..f5f7fd99e 100644 --- a/packages/web3/src/ethereum/demos/eip6963.tsx +++ b/packages/web3/src/ethereum/demos/eip6963.tsx @@ -1,5 +1,6 @@ import { ConnectButton, Connector } from '@ant-design/web3'; import { MetaMask, WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi'; +import { message } from 'antd'; import { createConfig, http } from 'wagmi'; import { mainnet } from 'wagmi/chains'; @@ -11,6 +12,7 @@ const config = createConfig({ }); const App: React.FC = () => { + const [messageApi, contextHolder] = message.useMessage(); return ( { }} wallets={[MetaMask()]} > - + { + messageApi.success(`Connected to ${account?.address}`); + }} + > + {contextHolder} ); }; diff --git a/packages/web3/src/types/index.md b/packages/web3/src/types/index.md index c37d55550..8acfcdf19 100644 --- a/packages/web3/src/types/index.md +++ b/packages/web3/src/types/index.md @@ -87,7 +87,7 @@ This is an enum type that contains the IDs of some commonly used chains. Its val | chain | Current chain | [Chain](#chain) | - | - | | availableChains | List of available chains | [Chain](#chain)\[] | - | - | | availableWallets | List of available wallets | [Wallet](#wallet)\[] | - | - | -| connect | Connect to the wallet | `(wallet: Wallet, options?: ConnectOptions) => Promise` | - | - | +| connect | Connect to the wallet | `(wallet: Wallet, options?: ConnectOptions) => Promise` | - | - | | disconnect | Disconnect from the chain | `() => Promise` | - | - | | switchChain | Switch to another chain | `(chainId: ChainIds) => Promise` | - | - | | getNFTMetadata | Get the metadata of the NFT | `(contractAddress: string, tokenId?: string) => Promise` | - | - | diff --git a/packages/web3/src/types/index.zh-CN.md b/packages/web3/src/types/index.zh-CN.md index c3d780b98..5875c389c 100644 --- a/packages/web3/src/types/index.zh-CN.md +++ b/packages/web3/src/types/index.zh-CN.md @@ -88,7 +88,7 @@ order: 3 | chain | 当前链 | [Chain](#chain) | - | - | | availableChains | 可以连接的链列表 | [Chain](#chain)[] | - | - | | availableWallets | 可用的钱包列表 | [Wallet](#wallet)[] | - | - | -| connect | 连接钱包 | `(wallet: Wallet, options?: ConnectOptions) => Promise` | - | - | +| connect | 连接钱包 | `(wallet: Wallet, options?: ConnectOptions) => Promise` | - | - | | disconnect | 断开钱包连接 | `() => Promise` | - | - | | switchChain | 切换链 | `(chain: Chain) => Promise` | - | - | | getNFTMetadata | 获取 NFT 的元数据 | `(params: { address: string; tokenId?: bigint \| number }) => Promise` | - | - |