ant-design/ant-design-web3

[Feature Request] SIWE signMessage demo

Closed this issue · 4 comments

Background

现在登录之后,往往会接着一次签名。是否可以做成一个配置项,在 connected 之后可以自动签名。

Proposal

目前想法可以参考 ConnectKit,它是设置了一个新的 Provider,然后在外面套了这一层内容

type SIWEConfig = {
  // Required
  getNonce: () => Promise<string>;
  createMessage: (args: { nonce: string; address: string; chainId: number }) => string;
  verifyMessage: (args: { message: string; signature: string }) => Promise<boolean>;
  getSession: () => Promise<SIWESession | null>;
  signOut: () => Promise<boolean>;
  // Optional
  enabled?: boolean; // defaults true
  nonceRefetchInterval?: number; // in milliseconds, defaults to 5 minutes
  sessionRefetchInterval?: number; // in milliseconds, defaults to 5 minutes
  signOutOnDisconnect?: boolean; // defaults true
  signOutOnAccountChange?: boolean; // defaults true
  signOutOnNetworkChange?: boolean; // defaults true
  onSignIn?: (session?: SIWESession) => void;
  onSignOut?: () => void;
};

需要考虑的是:1. 需要支持哪些;2. 执行的时机

Additional context

https://docs.family.co/connectkit/auth-with-custom-backend#siwe-custom-implementation

可以定义下我们支持的 API,大家一起 review 下看看

// 1. 添加一个 Provider 在 adapter 外层
<SIWEProvider {...siweConfig}>
  <WagmiWeb3ConfigProvider>
    ...
  </WagmiWeb3ConfigProvider>
</SIWEProvider>

// 2. siweConfig 支持的 api
{
  // required
  getNonce: () => Promise<string>;// 获取 nonce 
  createMessage: (args: { nonce: string; address: string; chainId: number }) => string; // 构建签名内容
  verifyMessage: (args: { message: string; signature: string }) => Promise<boolean>; // 验证签名
  getSession: () => Promise<{address: string, chainId: number} | null>; // 获取连接信息
  signOut: () => Promise<boolean>; // 签名失效的请求

  // options
  onSignIn?: (session?: SIWESession) => void; // 签名成功的回调
  onSignOut?: () => void; // 签名失效请求成功后的回调
}

// 3. 如何使用消费

const useSIWE = () => {
  enum StatusState {
    READY = 'ready',
    LOADING = 'loading',
    SUCCESS = 'success',
    REJECTED = 'rejected',
    ERROR = 'error',
  }

  return {
    status: StatusState, // 返回当前 SIWE 的状态
    signOut, // 包装后的签名失效回调
    signIn,  // 包装后的签名函数
  }
}

const SignMessageContent = () => {
  const {signIn} = useSIWE();

  return (
    <SIWEProvider {...siweConfig}>
      <WagmiWeb3ConfigProvider>
      <Connector
        onConnected={() => {
          signIn()
        }}
      >
        <ConnectButton />
      </Connector>
      </WagmiWeb3ConfigProvider>
    </SIWEProvider>
  )
}

想了一下我们可以直接在 WagmiWeb3ConfigProvider 上支持,不需要再加一个新的 Provider,感觉意义不大,另外我们需要把配置拆分到 UI 和 Adapter 中,设计上也有所不同:

import { Account, ConnectButton, Connector, Web3ConfigProviderProps } from '@ant-design/web3';
import { WagmiWeb3ConfigProvider } from '@ant-design/web3-wagmi';

export interface NewWeb3ConfigProviderProps extends Web3ConfigProviderProps {
  sign?: {
    // required
    signIn: (options: { address: string; chainId: number }) => Promise<void>;
    signOut: () => Promise<void>;

    // optional
    signOutOnDisconnect?: boolean; // defaults true
    signOutOnAccountChange?: boolean; // defaults true
    signOutOnNetworkChange?: boolean; // defaults true
  }; // Web3ConfigProviderProps 新增 sign 代表是否需要签名
}

export interface NewAccount extends Account {
  status?: 'unsign' | 'signed'; // Account 新增账号状态 status
}

export default () => {
  return (
    <WagmiWeb3ConfigProvider siwe={{
      getNonce: () => Promise<string>;
      createMessage: (args: { nonce: string; address: string; chainId: number }) => string;
      verifyMessage: (args: { message: string; signature: string }) => Promise<boolean>;
      getSession: () => Promise<SIWESession | null>;
      signOut: () => Promise<boolean>;
    }}>
      <Connector onSignIn={() => {}} onSignOut={() => {}}>
        <ConnectButton />
      </Connector>
    </WagmiWeb3ConfigProvider>
  );
};

from @Likang0122 的建议:通过 SIWEProvider 提供能够满足不同适配器的通用方案