Skip to content

Commit 647a081

Browse files
committed
feat: refactor sign siwe
1 parent 696de5b commit 647a081

File tree

13 files changed

+152
-137
lines changed

13 files changed

+152
-137
lines changed

packages/common/src/locale/en_US.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const localeValues: RequiredLocale = {
88
copied: 'Copied!',
99
walletAddress: 'Wallet address',
1010
moreWallets: 'More Wallets',
11+
sign: 'Sign',
1112
},
1213
ConnectModal: {
1314
title: 'Connect Wallet',

packages/common/src/locale/zh_CN.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const localeValues: RequiredLocale = {
88
copied: '复制成功!',
99
walletAddress: '钱包地址',
1010
moreWallets: '更多钱包',
11+
sign: '签名',
1112
},
1213
ConnectModal: {
1314
title: '连接钱包',

packages/common/src/types.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { type CreateSiweMessageParameters } from 'viem/siwe';
2-
31
export interface Account {
42
address: string;
53
name?: string;
@@ -121,7 +119,9 @@ export interface UniversalWeb3ProviderInterface {
121119

122120
// For Bitcoin, tokenId is undefined.
123121
getNFTMetadata?: (params: { address: string; tokenId?: bigint }) => Promise<NFTMetadata>;
124-
swie?: SWIEConfig;
122+
123+
// For Sign
124+
sign?: SignConfig;
125125
}
126126

127127
export interface Wallet extends WalletMetadata {
@@ -250,6 +250,7 @@ export interface RequiredLocale {
250250
copied: string;
251251
walletAddress: string;
252252
moreWallets: string;
253+
sign: string;
253254
};
254255
ConnectModal: {
255256
title: string;
@@ -333,21 +334,11 @@ export type Token = {
333334

334335
export interface SignConfig {
335336
// required
336-
signIn: (options: { address: string; chainId: number }) => Promise<void>;
337-
signOut: () => Promise<void>;
337+
signIn: (address: string, chain?: number) => Promise<void>;
338+
signOut?: () => Promise<void>;
338339

339340
// WIP: optional
340341
// signOutOnDisconnect?: boolean; // defaults true
341342
// signOutOnAccountChange?: boolean; // defaults true
342343
// signOutOnNetworkChange?: boolean; // defaults true
343344
}
344-
345-
export interface SWIEConfig {
346-
getNonce: (address: string, chainId?: number) => Promise<string>;
347-
createMessage: (args: CreateSiweMessageParameters) => string;
348-
verifyMessage: (message: string, signature: string) => Promise<boolean>;
349-
350-
// WIP: optional
351-
// getSession?: () => Promise<SIWESession | null>;
352-
// signOut?: () => Promise<boolean>;
353-
}

packages/common/src/web3-config-provider/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22

33
import defaultLocale from '../locale/default';
4-
import type { Locale, RequiredLocale, UniversalWeb3ProviderInterface } from '../types';
4+
import type { Locale, RequiredLocale, SignConfig, UniversalWeb3ProviderInterface } from '../types';
55

66
export interface Web3ConfigProviderProps extends UniversalWeb3ProviderInterface {
77
children?: React.ReactNode;

packages/wagmi/src/interface.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
WalletMetadata,
77
} from '@ant-design/web3-common';
88
import type { Chain as WagmiChain } from 'viem';
9+
import type { CreateSiweMessageParameters } from 'viem/siwe';
910
import type { Connector, CreateConnectorFn } from 'wagmi';
1011

1112
export interface WalletUseInWagmiAdapter extends Wallet {
@@ -31,3 +32,13 @@ export interface WalletFactory {
3132
export type EIP6963Config = boolean | UniversalEIP6963Config;
3233

3334
export type ChainAssetWithWagmiChain = Chain & { wagmiChain?: WagmiChain };
35+
36+
export interface SIWEConfig {
37+
getNonce: (address: string, chainId?: number) => Promise<string>;
38+
createMessage: (args: CreateSiweMessageParameters) => string;
39+
verifyMessage: (message: string, signature: string) => Promise<boolean>;
40+
41+
// WIP: optional
42+
// getSession?: () => Promise<SIWESession | null>;
43+
// signOut?: () => Promise<boolean>;
44+
}

packages/wagmi/src/wagmi-provider/config-provider.tsx

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import React from 'react';
22
import {
3-
SWIEConfig,
43
Web3ConfigProvider,
54
type Account,
65
type Chain,
76
type Locale,
87
type Wallet,
98
} from '@ant-design/web3-common';
9+
import { message } from 'antd';
1010
import type { Config as WagmiConfig } from 'wagmi';
1111
import {
1212
useAccount,
@@ -15,15 +15,22 @@ import {
1515
useConnect,
1616
useEnsAvatar,
1717
useEnsName,
18+
useSignMessage,
1819
useSwitchChain,
1920
type Connector as WagmiConnector,
2021
} from 'wagmi';
2122
import { disconnect, getAccount } from 'wagmi/actions';
2223

23-
import type { EIP6963Config, WalletFactory, WalletUseInWagmiAdapter } from '../interface';
24+
import type {
25+
EIP6963Config,
26+
SIWEConfig,
27+
WalletFactory,
28+
WalletUseInWagmiAdapter,
29+
} from '../interface';
2430
import { isEIP6963Connector } from '../utils';
2531
import { EIP6963Wallet } from '../wallets/eip6963';
2632
import { getNFTMetadata } from './methods';
33+
import { Mainnet } from '/packages/assets/src';
2734

2835
export interface AntDesignWeb3ConfigProviderProps {
2936
chainAssets: Chain[];
@@ -35,7 +42,7 @@ export interface AntDesignWeb3ConfigProviderProps {
3542
eip6963?: EIP6963Config;
3643
wagimConfig: WagmiConfig;
3744
useWalletConnectOfficialModal?: boolean;
38-
swie?: SWIEConfig;
45+
siwe?: SIWEConfig;
3946
}
4047

4148
export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderProps> = (props) => {
@@ -49,7 +56,7 @@ export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderPr
4956
eip6963,
5057
wagimConfig,
5158
useWalletConnectOfficialModal,
52-
swie,
59+
siwe,
5360
} = props;
5461
const { address, isDisconnected, chain } = useAccount();
5562
const config = useConfig();
@@ -58,6 +65,8 @@ export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderPr
5865
const { data: balanceData } = useBalance({ address });
5966
const { data: ensName } = useEnsName({ address });
6067
const { data: ensAvatar } = useEnsAvatar({ name: ensName ?? undefined });
68+
const { signMessageAsync } = useSignMessage();
69+
6170
const account: Account | undefined =
6271
address && !isDisconnected
6372
? {
@@ -189,13 +198,52 @@ export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderPr
189198
[chain?.id],
190199
);
191200

201+
const signIn = React.useCallback(
202+
async (signAddress: string, currentChainId?: number) => {
203+
if (!siwe) return;
204+
const { getNonce, createMessage, verifyMessage } = siwe;
205+
if (!signAddress) {
206+
throw new Error('Please connect wallet first.');
207+
}
208+
209+
// get nonce
210+
const nonce = await getNonce?.(signAddress);
211+
if (!nonce) {
212+
throw new Error('Failed to get nonce.');
213+
}
214+
215+
let msg: string;
216+
let signature: `0x${string}`;
217+
218+
try {
219+
msg = createMessage({
220+
domain: window.location.hostname,
221+
address: signAddress as `0x${string}`,
222+
uri: window.location.origin,
223+
nonce,
224+
// Default config
225+
version: '1',
226+
chainId: currentChainId ?? Mainnet.id,
227+
});
228+
signature = await signMessageAsync({ message: msg });
229+
console.log('get signature', signature);
230+
await verifyMessage(msg!, signature!);
231+
} catch (error: any) {
232+
throw new Error(error.message);
233+
}
234+
},
235+
[siwe, signMessageAsync],
236+
);
237+
192238
return (
193239
<Web3ConfigProvider
194240
locale={locale}
195241
availableChains={chainList}
196242
chain={currentChain}
197243
account={account}
198-
swie={swie}
244+
sign={{
245+
signIn,
246+
}}
199247
balance={
200248
balance
201249
? {

packages/wagmi/src/wagmi-provider/index.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import type { Locale, SWIEConfig } from '@ant-design/web3-common';
2+
import type { Locale } from '@ant-design/web3-common';
33
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
44
import type { Transport, Chain as WagmiChain } from 'viem';
55
import { createConfig, http, WagmiProvider } from 'wagmi';
@@ -10,7 +10,12 @@ import type { WalletConnectParameters } from 'wagmi/connectors';
1010

1111
// Built in popular chains
1212
import { Mainnet } from '../chains';
13-
import type { ChainAssetWithWagmiChain, EIP6963Config, WalletFactory } from '../interface';
13+
import type {
14+
ChainAssetWithWagmiChain,
15+
EIP6963Config,
16+
SIWEConfig,
17+
WalletFactory,
18+
} from '../interface';
1419
import { AntDesignWeb3ConfigProvider } from './config-provider';
1520

1621
export interface WalletConnectOptions
@@ -40,7 +45,7 @@ export interface WagmiWeb3ConfigProviderProps {
4045
reconnectOnMount?: boolean;
4146
walletConnect?: false | WalletConnectOptions;
4247
transports?: Record<number, Transport>;
43-
swie?: SWIEConfig;
48+
siwe?: SIWEConfig;
4449
}
4550

4651
export function WagmiWeb3ConfigProvider({
@@ -55,7 +60,7 @@ export function WagmiWeb3ConfigProvider({
5560
eip6963,
5661
walletConnect,
5762
transports,
58-
swie,
63+
siwe,
5964
...restProps
6065
}: React.PropsWithChildren<WagmiWeb3ConfigProviderProps>): React.ReactElement {
6166
// When user custom config, add Mainnet by default
@@ -139,7 +144,7 @@ export function WagmiWeb3ConfigProvider({
139144
balance={balance}
140145
eip6963={eip6963}
141146
wagimConfig={wagmiConfig}
142-
swie={swie}
147+
siwe={siwe}
143148
useWalletConnectOfficialModal={
144149
typeof walletConnect === 'object' && walletConnect?.useWalletConnectOfficialModal
145150
}

packages/web3/src/connect-button/connect-button.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useContext, useMemo, useState } from 'react';
22
import { CopyOutlined, LoginOutlined, UserOutlined } from '@ant-design/icons';
3-
import type { Chain, Wallet } from '@ant-design/web3-common';
3+
import { ConfigContext, type Chain, type Wallet } from '@ant-design/web3-common';
44
import type { ButtonProps } from 'antd';
55
import { Avatar, ConfigProvider, Divider, Dropdown, message } from 'antd';
66
import classNames from 'classnames';
@@ -13,7 +13,12 @@ import { fillWithPrefix, writeCopyText } from '../utils';
1313
import { ChainSelect } from './chain-select';
1414
import type { ChainSelectProps } from './chain-select';
1515
import { ConnectButtonInner } from './connect-button-inner';
16-
import type { ConnectButtonProps, ConnectButtonTooltipProps, MenuItemType } from './interface';
16+
import {
17+
ConnectButtonStatus,
18+
type ConnectButtonProps,
19+
type ConnectButtonTooltipProps,
20+
type MenuItemType,
21+
} from './interface';
1722
import type { ProfileModalProps } from './profile-modal';
1823
import { ProfileModal } from './profile-modal';
1924
import { useStyle } from './style';
@@ -40,6 +45,8 @@ export const ConnectButton: React.FC<ConnectButtonProps> = (props) => {
4045
locale,
4146
quickConnect,
4247
addressPrefix: addressPrefixProp,
48+
connectStatus,
49+
onConnectStatusChange,
4350
...restProps
4451
} = props;
4552
const intl = useIntl('ConnectButton', locale);
@@ -50,8 +57,11 @@ export const ConnectButton: React.FC<ConnectButtonProps> = (props) => {
5057
const { wrapSSR, hashId } = useStyle(prefixCls);
5158
const [messageApi, contextHolder] = message.useMessage();
5259
const [showMenu, setShowMenu] = useState(false);
60+
const { sign } = React.useContext(ConfigContext);
5361

62+
const needSign = sign?.signIn && connectStatus === 'connected' && account;
5463
let buttonText: React.ReactNode = intl.getMessage(intl.messages.connect);
64+
5565
if (account) {
5666
buttonText =
5767
account?.name && !balance ? (
@@ -68,19 +78,36 @@ export const ConnectButton: React.FC<ConnectButtonProps> = (props) => {
6878
);
6979
}
7080

81+
if (needSign) {
82+
buttonText = (
83+
<>
84+
{`${intl.getMessage(intl.messages.sign)}: `}:{buttonText}
85+
</>
86+
);
87+
}
88+
7189
const buttonProps: ButtonProps = {
7290
style: props.style,
7391
size: props.size,
7492
type: props.type,
7593
ghost: props.ghost,
7694
loading,
7795
className: classNames(className, prefixCls, hashId),
78-
onClick: (e) => {
96+
onClick: async (e) => {
7997
setShowMenu(false);
80-
if (account && !profileOpen && profileModal) {
98+
if (account && !profileOpen && profileModal && !needSign) {
8199
setProfileOpen(true);
82100
}
83101
onClick?.(e);
102+
103+
try {
104+
if (needSign) {
105+
await sign?.signIn?.(account?.address, chain?.id);
106+
onConnectStatusChange?.(ConnectButtonStatus.Signed);
107+
}
108+
} catch (error: any) {
109+
messageApi.error(error.message);
110+
}
84111
},
85112
...restProps,
86113
};

packages/web3/src/connect-button/interface.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import type { AvatarProps, ButtonProps, GetProp, MenuProps, TooltipProps } from
44
import type { AddressProps } from '../address';
55
import type { ProfileModalProps } from './profile-modal';
66

7+
export const enum ConnectButtonStatus {
8+
Connected = 'connected',
9+
Disconnected = 'disconnected',
10+
Signed = 'signed',
11+
}
12+
713
export type MenuItemType = Extract<GetProp<MenuProps, 'items'>[number], { type?: 'item' }>;
814

915
export type ConnectButtonTooltipProps = TooltipProps & {
@@ -18,6 +24,8 @@ export type ConnectButtonProps = ButtonProps &
1824
prefixCls?: string;
1925
locale?: Locale['ConnectButton'];
2026
avatar?: AvatarProps;
27+
connectStatus?: ConnectButtonStatus;
28+
onConnectStatusChange?: (status: ConnectButtonStatus) => void;
2129
onMenuItemClick?: (e: NonNullable<MenuProps['items']>[number]) => void;
2230
tooltip?: boolean | ConnectButtonTooltipProps;
2331
profileModal?: boolean | ProfileModalProps['modalProps'];

0 commit comments

Comments
 (0)