本文へ移動

外部EVMウォレット

秘密鍵を取り込まずに、MetaMask、Rabby、PhantomのEVMアカウントを接続します。

外部EVMウォレット ​

@seams/walletは、秘密鍵を取り込まずに、既存のMetaMask、Rabby、PhantomのEVMアカウントに接続できます。 アプリが、検出したプロバイダーを選択します。アカウントへのアクセス許可と、すべての承認画面は、ウォレット拡張機能が管理します。

このコネクターはホスト側で動作し、Seamsのウォレットセッションを必要としません。 フレームワークに依存せずに使う場合は、@seams/wallet/external-evmからExternalEvmControllerをインポートします。 Reactアプリでは、以下のピッカーとフックを使えます。

React以外では、ホストUIのマウント時にcontroller.start(window)、アンマウント時にcontroller.dispose()を呼び出してください。

tsx
import { useMemo } from 'react';
import {
  ExternalEvmController,
  ExternalEvmWalletPicker,
  useExternalEvm,
  type ExternalEvmConnection,
} from '@seams/wallet/react';

function createExternalEvmController(): ExternalEvmController {
  return new ExternalEvmController([
    {
      chainId: 11_155_111,
      name: 'Sepolia testnet',
      rpcUrl: 'https://rpc.sepolia.org',
    },
  ]);
}

async function signExternalMessage(
  controller: ExternalEvmController,
  connection: ExternalEvmConnection,
): Promise<void> {
  await controller.signMessage(connection, new TextEncoder().encode('Approve this application'));
}

export function ExternalWalletSection() {
  const controller = useMemo(createExternalEvmController, []);
  const externalEvm = useExternalEvm(controller);
  const { connection } = externalEvm;

  return (
    <>
      <ExternalEvmWalletPicker controller={controller} snapshot={externalEvm} />
      {connection.kind === 'connected' ? (
        <button type="button" onClick={signExternalMessage.bind(null, controller, connection)}>
          Sign message
        </button>
      ) : null}
    </>
  );
}

コントローラーは、EIP-6963で通知されたプロバイダーを検出します。 Phantomの拡張機能がEIP-6963の通知を省く場合があるため、公式に定義されたwindow.phantom.ethereumも確認します。 共有のwindow.ethereumプロバイダーを選ぶことはありません。選択した各プロバイダーは、EIP-1193経由で呼び出します。 コントローラーは、アカウント、チェーン、切断のイベントを扱います。 要求の拒否、非対応のメソッドやネットワーク、不正なプロバイダー応答、古い接続、結果が不明な取引について、型付きの対処可能な失敗結果を返します。

最初のリリースは、デスクトップのEVM拡張機能、設定済みチェーンへの切り替え、personal_sign、 EIP-712のeth_signTypedData_v4、通常のeth_sendTransaction、設定済みRPC URLでのレシート確認に対応します。 各チェーンには、数値のEVMチェーンID、表示名、HTTPSまたはHTTPのJSON-RPCエンドポイントを設定してください。 コントローラーは、送信した取引を検証するためだけに、このRPCエンドポイントを使います。 署名とブロードキャストは、ウォレットプロバイダーが行います。

各操作には、対象のアカウントとチェーンのスナップショットとしてconnectionを使ってください。 アカウントやチェーンのイベント後に識別情報が古くなった場合、コントローラーはconnection_changedを返します。 新しいスナップショットを読み取り、ユーザーに再試行を求めてください。 返された取引ハッシュは、送信を行った証拠です。要求の送出後にプロバイダーが失敗した場合は、 submission_unknownを返し、自動的に再送することはありません。

切断すると、このアプリのプロバイダー用リスナーとローカル状態を解除します。 MetaMask、Rabby、Phantomにあるサイトのアクセス許可は取り消しません。 その許可は、ユーザーが外部ウォレットで管理します。

レシートを待つ ​

sendTransactionが送信成功の結果を返したら、 await controller.waitForReceipt(submission, { timeoutMs: 90_000, signal })を呼び出します。 コントローラーは設定済みRPCをポーリングし、レシートのチェーン、取引ハッシュ、アカウント、ステータス、ブロック番号を検証します。

結果はconfirmed、reverted、unresolvedのいずれかです。 confirmedは、1つのブロックに含まれたことを意味します。チェーンのファイナリティが必要なアプリでは、別途追跡してください。 タイムアウト、キャンセル、RPCの失敗、レシートを検証できない場合は、unresolvedを返します。 送信済みのハッシュを保持し、ユーザーが確認できるようにしてください。自動で再送しないでください。 キャンセル時は、進行中のRPC要求が完了するまで待つ場合があります。

拡張機能の動作確認 ​

このコネクターを使うアプリを公開する前に、Console Liteの実装例で確認してください。

  1. 新規のデスクトップブラウザープロファイルで、MetaMask、Rabby、Phantom EVMを1つずつ有効にして実行します。
  2. インストールしたすべての拡張機能を同時に有効にして、再度確認します。
  3. ブラウザーと拡張機能のバージョンを記録します。
  4. 各ウォレットで、プロバイダーの検出、ウォレットの明示的な選択、アカウントの選択、設定済みネットワークへの切り替えを確認します。
  5. メッセージ署名、型付きデータへの署名、テストネット取引を確認します。
  6. 各承認を、一度ずつ拒否します。
  7. アプリ側で接続を解除します。
  8. 後続の試行で、新しい要求が開始されることを確認します。
  9. 取引の要求後に、プロバイダーとの通信を切断します。
  10. UIが結果不明の状態を表示し、自動で再送しないことを確認します。

外部アカウントは、Seamsの鍵管理や認証とは別のものです。 接続しても、Seamsへのログイン、ウォレットセッションの作成、Seamsウォレットの操作権限の付与は行いません。 モバイル向け接続、WalletConnect、Solana、アカウントのリンク、鍵管理用の秘密情報の取り込みは、このコネクターの対象外です。

EIP-6963、EIP-1193、 PhantomのEVMプロバイダードキュメントも参照してください。