Skip to content

Commit 08c5321

Browse files
yutingzhao1991tingzhao.ytzthinkasanygin-lsl
authored
docs: add SIWE demo (#1199)
* docs: add SIWE demo * Update packages/web3/src/ethereum/index.zh-CN.md Co-authored-by: thinkasany <[email protected]> * fix: lint issue * fix: lint issue * chore: update test config * chore: remove useless test config * Update packages/web3/src/ethereum/demos/siwe/sign-btn.tsx Co-authored-by: thinkasany <[email protected]> * Apply suggestions from code review --------- Co-authored-by: tingzhao.ytz <[email protected]> Co-authored-by: thinkasany <[email protected]> Co-authored-by: gin-lsl <[email protected]>
1 parent d3786c8 commit 08c5321

File tree

6 files changed

+153
-1
lines changed

6 files changed

+153
-1
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { ConnectButton, Connector } from '@ant-design/web3';
2+
import {
3+
Mainnet,
4+
MetaMask,
5+
OkxWallet,
6+
TokenPocket,
7+
WagmiWeb3ConfigProvider,
8+
WalletConnect,
9+
} from '@ant-design/web3-wagmi';
10+
import { QueryClient } from '@tanstack/react-query';
11+
import { http } from 'wagmi';
12+
13+
import SignBtn from './sign-btn';
14+
15+
const queryClient = new QueryClient();
16+
17+
const App: React.FC = () => {
18+
return (
19+
<WagmiWeb3ConfigProvider
20+
eip6963={{
21+
autoAddInjectedWallets: true,
22+
}}
23+
ens
24+
chains={[Mainnet]}
25+
transports={{
26+
[Mainnet.id]: http(),
27+
}}
28+
walletConnect={{
29+
projectId: YOUR_WALLET_CONNECT_PROJECT_ID,
30+
}}
31+
wallets={[
32+
MetaMask(),
33+
WalletConnect(),
34+
TokenPocket({
35+
group: 'Popular',
36+
}),
37+
OkxWallet(),
38+
]}
39+
queryClient={queryClient}
40+
>
41+
<SignBtn />
42+
</WagmiWeb3ConfigProvider>
43+
);
44+
};
45+
46+
export default App;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export async function getNonce(chainAddress: string) {
2+
// mock getNonce
3+
return 'PtZZs3w7ktHsbSFUcmwb';
4+
}
5+
6+
export async function verifyMessage(message: string, signature: string) {
7+
// mock verifyMessage
8+
return true;
9+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { useCallback, useState } from 'react';
2+
import { Account, ConnectButton, Connector, useAccount } from '@ant-design/web3';
3+
import { Mainnet } from '@ant-design/web3-wagmi';
4+
import { Button, message, Space } from 'antd';
5+
import { createSiweMessage } from 'viem/siwe';
6+
import { useSignMessage } from 'wagmi';
7+
8+
import { getNonce, verifyMessage } from './mock-api';
9+
10+
export default function App() {
11+
const { account } = useAccount();
12+
13+
const [signed, setSigned] = useState<boolean>(false);
14+
const [signLoading, setSignLoading] = useState<boolean>(false);
15+
const { signMessageAsync } = useSignMessage();
16+
17+
const signIn = useCallback(async (a?: Account) => {
18+
const address = a?.address as `0x${string}`;
19+
20+
if (!address) {
21+
message.error('Please connect wallet first.');
22+
return;
23+
}
24+
25+
// get nonce
26+
const nonce = await getNonce(address);
27+
if (!nonce) {
28+
message.error('Failed to get nonce.');
29+
return;
30+
}
31+
32+
let msg: string;
33+
let signature: `0x${string}`;
34+
35+
try {
36+
msg = createSiweMessage({
37+
domain: window.location.hostname,
38+
address,
39+
statement: 'Sign in with Ethereum',
40+
uri: window.location.origin,
41+
version: '1',
42+
chainId: Mainnet.id,
43+
nonce,
44+
});
45+
setSignLoading(true);
46+
console.log('signing message');
47+
signature = await signMessageAsync({ message: msg });
48+
console.log('get signature', signature);
49+
await verifyMessage(msg!, signature!);
50+
message.success('Sign in successfully.');
51+
setSigned(true);
52+
setSignLoading(false);
53+
} catch (error: any) {
54+
message.error(error.message);
55+
setSignLoading(false);
56+
}
57+
}, []);
58+
59+
return (
60+
<Space>
61+
<Connector
62+
modalProps={{
63+
mode: 'simple',
64+
}}
65+
onDisconnected={() => {
66+
setSigned(false);
67+
}}
68+
onConnected={(a) => signIn(a)}
69+
>
70+
<ConnectButton />
71+
</Connector>
72+
{!signed && account && (
73+
<Button
74+
type="primary"
75+
loading={signLoading}
76+
onClick={() => {
77+
signIn(account);
78+
}}
79+
>
80+
Sign
81+
</Button>
82+
)}
83+
</Space>
84+
);
85+
}

packages/web3/src/ethereum/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ We have built-in `Mainnet`, and the remaining chains need to configure `chains`
6666

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

69+
## SIWE
70+
71+
SIWE means Sign-In with Ethereum. Your website can verify user login through signatures. Below is an example where the backend interface is mocked. You need to implement it in your project.
72+
73+
<code src="./demos/siwe/index.tsx"></code>
74+
6975
## Display ENS and Balance
7076

7177
> You need to connect to an address containing ENS and balance to see the example effect.

packages/web3/src/ethereum/index.zh-CN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ Ant Design Web3 官方提供了 `wagmi`、`ethers` 等多个框架的适配器
6565

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

68+
## SIWE
69+
70+
SIWE 是指 Sign-In with Ethereum,你的网站可以通过签名来验证用户的登录,下面是一个示例,其中后端接口做了 Mock,你需要在你的项目中自行实现。
71+
72+
<code src="./demos/siwe/index.tsx"></code>
73+
6874
## 显示 ENS 和余额
6975

7076
> 你需要连接包含 ENS 和余额 的地址才能看到示例效果

vitest.config.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default defineConfig({
6868
coverage: {
6969
include: ['packages/*/src/**/*.{ts,tsx}'],
7070
exclude: [
71-
'**/demos/*.{ts,tsx}',
71+
'**/demos/**/*.{ts,tsx}',
7272
'**/src/index.ts',
7373
'**/__tests__/*.{ts,tsx}',
7474
'**/*.test.{ts,tsx}',

0 commit comments

Comments
 (0)