本文へ移動

デバイス連携・鍵のエクスポート・復元

新たな承認を受けて、別のデバイスの連携、鍵のエクスポート、ウォレットアカウントの復元を行います。

デバイス連携・鍵のエクスポート・復元 ​

最初のウォレットで署名できるようになったら、これらの機能を追加します。 各操作は独自の承認と結果を持ちます。通常の署名とは別の処理として扱ってください。

デバイス2がリンクセッションを開始し、QRコードを表示します。 デバイス1がコードを読み取り、新しいデバイスを承認します。

tsx
import { useState } from 'react';
import { QRScanMode, ShowQRCode, useDeviceLinking } from '@seams/wallet/react';
import type { LinkDeviceFlowEvent, QrLinkedDeviceSessionPayloadV5 } from '@seams/wallet';

function logLinkEvent(event: LinkDeviceFlowEvent): void {
  console.log(event.phase, event.status, event.message);
}

// Device 2: `ShowQRCode` runs the whole start/display/expire cycle, including
// picking the target factor and cancelling an abandoned session.
export function NewDeviceLinkCode() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Show link code</button>
      <ShowQRCode
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        onEvent={logLinkEvent}
        onError={(error) => console.error('Device link failed', error)}
      />
    </>
  );
}

// Device 1: scan the code and approve.
export function ApproveLinkedDevice(props: { qrData: QrLinkedDeviceSessionPayloadV5 }) {
  const { linkDevice } = useDeviceLinking({
    onEvent: logLinkEvent,
    onError: (error) => console.error('Device link failed', error),
  });

  return (
    <button onClick={() => void linkDevice(props.qrData, QRScanMode.CAMERA)}>Approve device</button>
  );
}

デバイス2では、ShowQRCodeがリンクセッションを開始し、コードを表示します。 画面を閉じると、未完了のセッションをキャンセルします。 デバイス1では、useDeviceLinkingがonEventで進行状況、onErrorで失敗を通知します。 試行ごとに新しいコードを発行してください。

鍵をエクスポート ​

新たに承認した操作からexportKeyを呼び出します。 エクスポート対象のレーンを選択し、ウォレットオリジンのエクスポートビューアーを開きます。

ts
import { logWalletEvents, type SeamsWeb } from '@seams/wallet';

export async function exportNearKey(seams: SeamsWeb): Promise<void> {
  await seams.keys.exportKey({
    kind: 'ed25519',
    options: { onEvent: logWalletEvents() },
  });
}

export async function exportEvmKey(seams: SeamsWeb): Promise<void> {
  await seams.keys.exportKey({
    kind: 'ecdsa',
    chainTarget: 'tempo-testnet',
    options: { onEvent: logWalletEvents() },
  });
}

Ed25519のエクスポートは、ウォレットのNEARアカウントを使います。 ECDSAのエクスポートでは、設定済みチェーンを指定します。どちらも、既定ではログイン中のウォレットを対象とします。 ウォレット、アカウント、チェーンを明示する場合は、walletSession、nearAccount、chainTargetを渡してください。

レーンの選択はSDKが行い、選択したレーンをウォレットオリジンのビューアーへ直接渡します。 このデバイスに対象のエクスポートレーンや鍵素材がない場合、exportKeyはレーンまたは鍵素材に関するエラーでrejectされます。

鍵素材はウォレットオリジンのビューアー内に表示されます。 アプリが受け取るのはexportedなどの結果であり、秘密鍵は含まれません。 エクスポートの内容を、ログ、URL、アクセス解析に含めないでください。

ウォレットアカウントを復元 ​

復元処理でウォレットに紐づくアカウント情報を復元する必要がある場合は、ウォレットレコードを同期します。

syncAccountは、既知のウォレットのアカウント状態を同期します。 復元コードの入力と新しい認証要素の検証は、ホスト型ウォレットメニューが担当します。 ウォレットユーザーの復元を参照してください。

ts
import type { SeamsWeb } from '@seams/wallet';

type SyncAccountResult = Awaited<ReturnType<SeamsWeb['recovery']['syncAccount']>>;

export async function recoverWalletAccount(
  seams: SeamsWeb,
  walletId: string,
): Promise<SyncAccountResult> {
  const result = await seams.recovery.syncAccount({ walletId });
  if (!result.success) {
    throw new Error(result.error);
  }

  console.log('wallet account restored', result.walletId, result.nearAccountId);
  return result;
}

walletIdやnearAccountIdを読む前に、successを確認してください。 同期が失敗するとヘルパーは例外を送出するため、呼び出し側で再試行の状態を表示できます。

権限の委任と鍵のローテーション ​

エージェントへの権限委任、レーンの更新、鍵のローテーションには、製品に応じたポリシーとデプロイの選択が必要です。 権限を委任したエージェント、リンク済みデバイス、 復元・エクスポート・鍵のローテーションから確認してください。

安全な再試行 ​

  • キャンセルやセッションの期限切れの後は、新たな承認を求めてください。
  • 古いセッションでエクスポートや鍵のローテーションを再試行しないでください。
  • 署名を許可しなくなったデバイスや委任レーンは、権限を取り消してください。