Skip to content

Add devices, export, and recover

Link another device, export a key, or restore a wallet account through fresh authorization.

Add devices, export, and recover ​

Use these flows after your first wallet can sign. Each operation has its own authorization and result. Handle each operation separately from normal signing.

Device 2 starts a link session and displays a QR code. Device 1 scans that code and approves the new device.

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>
  );
}

On Device 2, ShowQRCode starts the link session and displays the code. It cancels an abandoned session when closed. On Device 1, useDeviceLinking reports progress through onEvent and failures through onError. Request a fresh code for each attempt.

Export a key ​

Call exportKey from a freshly authorized action. It selects the exact export lane and opens the export viewer on the wallet origin.

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 export uses the wallet's NEAR account. ECDSA export names a configured chain. Both default to the signed-in wallet. Pass walletSession, nearAccount, or chainTarget to select the exact wallet, account, or chain.

The SDK owns lane selection and passes the selected lane directly to the wallet-origin viewer. If this device has no exact export lane or material, exportKey rejects with an export-lane or material error.

Key material is displayed inside the wallet-origin viewer. The app receives an outcome, such as exported, without the private key. Keep export content out of logs, URLs, and analytics.

Recover a wallet account ​

Synchronize the wallet record when your recovery flow needs to restore its wallet-scoped account identity.

syncAccount synchronizes a known wallet's account state. Recovery-code entry and new-factor verification belong to the hosted wallet menu. See wallet-user recovery.

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;
}

Check success before reading walletId or nearAccountId. The helper throws for a failed synchronization so the caller can render a retry state.

Delegation and rotation ​

Delegated agents, lane refresh, and key rotation add policy and deployment choices that depend on your product. Start with delegated agents, linked devices, or recovery, export, and rotation.

Safe retries ​

  • Ask for fresh authorization after cancellation or session expiry.
  • Do not retry export or rotation with a stale session.
  • Revoke a linked device or delegated lane when it should no longer sign.