Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add swie #1214

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/common/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { type CreateSiweMessageParameters } from 'viem/siwe';

export interface Account {
address: string;
name?: string;
Expand Down Expand Up @@ -119,6 +121,7 @@ export interface UniversalWeb3ProviderInterface {

// For Bitcoin, tokenId is undefined.
getNFTMetadata?: (params: { address: string; tokenId?: bigint }) => Promise<NFTMetadata>;
swie?: SWIEConfig;
}

export interface Wallet extends WalletMetadata {
Expand Down Expand Up @@ -327,3 +330,24 @@ export type Token = {
contract?: string;
}[];
};

export interface SignConfig {
// required
signIn: (options: { address: string; chainId: number }) => Promise<void>;
signOut: () => Promise<void>;

// WIP: optional
// signOutOnDisconnect?: boolean; // defaults true
// signOutOnAccountChange?: boolean; // defaults true
// signOutOnNetworkChange?: boolean; // defaults true
}

export interface SWIEConfig {
getNonce: (address: string, chainId?: number) => Promise<string>;
createMessage: (args: CreateSiweMessageParameters) => string;
verifyMessage: (message: string, signature: string) => Promise<boolean>;

// WIP: optional
// getSession?: () => Promise<SIWESession | null>;
// signOut?: () => Promise<boolean>;
}
1 change: 0 additions & 1 deletion packages/common/src/web3-config-provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const ProviderChildren: React.FC<
ConfigConsumerProps & { children?: React.ReactNode; parentContext?: ConfigConsumerProps }
> = (props) => {
const { children, parentContext, ...rest } = props;

const config = { ...parentContext };

Object.keys(rest).forEach((key) => {
Expand Down
4 changes: 4 additions & 0 deletions packages/wagmi/src/wagmi-provider/config-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import {
SWIEConfig,
Web3ConfigProvider,
type Account,
type Chain,
Expand Down Expand Up @@ -34,6 +35,7 @@ export interface AntDesignWeb3ConfigProviderProps {
eip6963?: EIP6963Config;
wagimConfig: WagmiConfig;
useWalletConnectOfficialModal?: boolean;
swie?: SWIEConfig;
}

export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderProps> = (props) => {
Expand All @@ -47,6 +49,7 @@ export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderPr
eip6963,
wagimConfig,
useWalletConnectOfficialModal,
swie,
} = props;
const { address, isDisconnected, chain } = useAccount();
const config = useConfig();
Expand Down Expand Up @@ -192,6 +195,7 @@ export const AntDesignWeb3ConfigProvider: React.FC<AntDesignWeb3ConfigProviderPr
availableChains={chainList}
chain={currentChain}
account={account}
swie={swie}
balance={
balance
? {
Expand Down
10 changes: 6 additions & 4 deletions packages/wagmi/src/wagmi-provider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import type { Locale } from '@ant-design/web3-common';
import type { Locale, SWIEConfig } from '@ant-design/web3-common';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import type { Transport, Chain as WagmiChain } from 'viem';
import { createConfig, http, WagmiProvider } from 'wagmi';
Expand Down Expand Up @@ -27,7 +27,7 @@ export interface WalletConnectOptions
useWalletConnectOfficialModal?: boolean;
}

export type WagmiWeb3ConfigProviderProps = {
export interface WagmiWeb3ConfigProviderProps {
config?: Config;
locale?: Locale;
wallets?: WalletFactory[];
Expand All @@ -40,7 +40,8 @@ export type WagmiWeb3ConfigProviderProps = {
reconnectOnMount?: boolean;
walletConnect?: false | WalletConnectOptions;
transports?: Record<number, Transport>;
};
swie?: SWIEConfig;
}

export function WagmiWeb3ConfigProvider({
children,
Expand All @@ -54,6 +55,7 @@ export function WagmiWeb3ConfigProvider({
eip6963,
walletConnect,
transports,
swie,
...restProps
}: React.PropsWithChildren<WagmiWeb3ConfigProviderProps>): React.ReactElement {
// When user custom config, add Mainnet by default
Expand All @@ -63,7 +65,6 @@ export function WagmiWeb3ConfigProvider({
: chains?.length
? chains
: [Mainnet];

const generateConfigFlag = () => {
return `${JSON.stringify(walletConnect)}-${chains.map((item) => item.id).join(',')}-${wallets.map((item) => item.name).join(',')}`;
};
Expand Down Expand Up @@ -138,6 +139,7 @@ export function WagmiWeb3ConfigProvider({
balance={balance}
eip6963={eip6963}
wagimConfig={wagmiConfig}
swie={swie}
useWalletConnectOfficialModal={
typeof walletConnect === 'object' && walletConnect?.useWalletConnectOfficialModal
}
Expand Down
8 changes: 7 additions & 1 deletion packages/web3/src/ethereum/demos/siwe/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ConnectButton, Connector } from '@ant-design/web3';
import {
Mainnet,
MetaMask,
Expand All @@ -8,15 +7,22 @@ import {
WalletConnect,
} from '@ant-design/web3-wagmi';
import { QueryClient } from '@tanstack/react-query';
import { createSiweMessage } from 'viem/siwe';
import { http } from 'wagmi';

import { getNonce, verifyMessage } from './mock-api';
import SignBtn from './sign-btn';

const queryClient = new QueryClient();

const App: React.FC = () => {
return (
<WagmiWeb3ConfigProvider
swie={{
getNonce,
createMessage: (props) => createSiweMessage({ ...props, statement: 'Ant Design Web3' }),
verifyMessage: verifyMessage,
}}
eip6963={{
autoAddInjectedWallets: true,
}}
Expand Down
57 changes: 4 additions & 53 deletions packages/web3/src/ethereum/demos/siwe/sign-btn.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,11 @@
import { useCallback, useState } from 'react';
import { Account, ConnectButton, Connector, useAccount } from '@ant-design/web3';
import { Mainnet } from '@ant-design/web3-wagmi';
import { Button, message, Space } from 'antd';
import { createSiweMessage } from 'viem/siwe';
import { useSignMessage } from 'wagmi';
import { ConnectButton, Connector, useAccount } from '@ant-design/web3';
import { Button, Space } from 'antd';

import { getNonce, verifyMessage } from './mock-api';
import { useSwie } from './useSwie';

export default function App() {
const { account } = useAccount();

const [signed, setSigned] = useState<boolean>(false);
const [signLoading, setSignLoading] = useState<boolean>(false);
const { signMessageAsync } = useSignMessage();

const signIn = useCallback(async (a?: Account) => {
const address = a?.address as `0x${string}`;

if (!address) {
message.error('Please connect wallet first.');
return;
}

// get nonce
const nonce = await getNonce(address);
if (!nonce) {
message.error('Failed to get nonce.');
return;
}

let msg: string;
let signature: `0x${string}`;

try {
msg = createSiweMessage({
domain: window.location.hostname,
address,
statement: 'Sign in with Ethereum',
uri: window.location.origin,
version: '1',
chainId: Mainnet.id,
nonce,
});
setSignLoading(true);
console.log('signing message');
signature = await signMessageAsync({ message: msg });
console.log('get signature', signature);
await verifyMessage(msg!, signature!);
message.success('Sign in successfully.');
setSigned(true);
setSignLoading(false);
} catch (error: any) {
message.error(error.message);
setSignLoading(false);
}
}, []);
const { signLoading, signed, signIn, setSigned } = useSwie();

return (
<Space>
Expand Down
67 changes: 67 additions & 0 deletions packages/web3/src/ethereum/demos/siwe/useSwie.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { useCallback, useState } from 'react';
import { Account, useProvider } from '@ant-design/web3';
import { Mainnet } from '@ant-design/web3-wagmi';
import { message } from 'antd';
import { useSignMessage } from 'wagmi';

const DefaultSignInfo = {};

export const useSwie = () => {
const { swie } = useProvider();
const [signLoading, setSignLoading] = useState<boolean>(false);
const { signMessageAsync } = useSignMessage();
const [signed, setSigned] = useState<boolean>(false);

const signIn = useCallback(async (a?: Account) => {
if (!swie) return;

const { getNonce, createMessage, verifyMessage } = swie;

const address = a?.address as `0x${string}`;

if (!address) {
message.error('Please connect wallet first.');
return;
}

// get nonce
const nonce = await getNonce?.(address);
if (!nonce) {
message.error('Failed to get nonce.');
return;
}

let msg: string;
let signature: `0x${string}`;

try {
msg = createMessage({
domain: window.location.hostname,
address,
uri: window.location.origin,
nonce,
// Default config
version: '1',
chainId: Mainnet.id,
});
setSignLoading(true);
console.log('signing message');
signature = await signMessageAsync({ message: msg });
console.log('get signature', signature);
await verifyMessage(msg!, signature!);
message.success('Sign in successfully.');
setSigned(true);
setSignLoading(false);
} catch (error: any) {
message.error(error.message);
setSignLoading(false);
}
}, []);

return {
signLoading,
signed,
signIn,
setSigned,
};
};
Loading