# React SDK

Selected public API snapshot of @shard-lab/nc-waas-react.

Selected Privy-compatible public API declarations from `@shard-lab/nc-waas-react` (the Pouchi Wallet React SDK). Entry points: `.` (React), `./server`, `./wagmi`, `./smart-wallets`, `./solana`, `./core` (no React).

## Hooks at a glance

| Name | What it does | Status |
|---|---|---|
| `PrivyProvider`, `NcWaasProvider` | Provider that wraps the app. `apiUrl`, `appId` (or `tenantId`), `config.defaultChain` (or `chain`) | Supported |
| `usePrivy` | `ready`, `authenticated`, `user`, `login`, `logout`, `getAccessToken`, `signMessage`, `exportWallet` (explanation only), account linking | Supported |
| `useLogin`, `useLogout` | Open and complete the login modal, logout callbacks | Supported |
| `useLoginWithEmail` | Email code login. New users complete wallet protection on the Pouchi screen (`sendCode`, `loginWithCode`) | Supported |
| `useLoginWithOAuth` | google, apple, kakao, naver login. The tenant must turn it on and register the redirect URI | Needs tenant setup |
| `useLinkAccount` | Link email, social, passkey. Other methods reject through `onError` | Supported |
| `useLoginWithPasskey` | Log in with a registered passkey | Supported |
| `useSignupWithPasskey` | Sign up with a passkey only | Not supported (rejects) |
| `useWallets` | One embedded smart wallet and its EIP-1193 provider | Supported |
| `useSendTransaction` | Transfers, ERC-20, contract calls. `{ hash }` after the approval screen | Supported |
| `useSignMessage`, `useSignTypedData` | ERC-1271 signatures (including EIP-712) | Supported |
| `useSendCalls`, `useSmartWallets` | Batches (EIP-5792, up to 8 calls) and the Privy smart wallet client | Supported |
| `useSessionApproval` | In-app session key delegation. Needs `config.approvals.session.clientId` | Supported |
| `useWalletRecovery`, `useRecoverWallet` | Move the wallet to a new device, see a recovery in progress | Supported |
| `useRecoveryBackups` | List and delete backup methods | Supported |
| `useSessions`, `useRevokeSession`, `LoggedInDevices` | Logged-in devices and logging them out | Supported |
| `AssetMigrationCard`, `useAssetMigration` | Move assets from the old Privy wallet to the new wallet | Supported |
| `useCreateWallet` | Returns the wallet created at first login. Additional wallets reject | Partly supported |
| `useSessionSigners` | Privy session signers | Not supported (rejects). `useSessionApproval` or server delegation |
| `useSignTransaction` | Raw transaction signing | Not supported (rejects). `useSendTransaction` |
| `useFundWallet`, `useImportWallet`, `useCrossAppAccounts`, `useMfaEnrollment`, `useMfa`, `useSolanaWallets` | Privy-only features | Not supported (rejects or empty) |
| `useNcWaas`, `useNcWaasState` | Controller and state for building your own screens | Advanced |

**Declaration source**
Extracted from the installed artifact of `@shard-lab/nc-waas-react@0.1.0`. This does not establish registry availability or a completed live integration. This reference covers selected APIs.

Declarations SHA256: `b5cfde74b3aed3695dc5519e36e396453ca72c220c5b3251c2c9f0e5e2ffa1a1`

Package archive SHA256: `16c193678e9ad0632466f56c56edf07f8db4f62a5431f6153678701c8a14c958`

## Provider

### PrivyProvider

function · react/provider.d.ts

Privy-compatible name. Migration also requires the Pouchi API URL, app ID and chain configuration.

```ts
const PrivyProvider: typeof NcWaasProvider;
```

### NcWaasProvider

function · react/provider.d.ts

```ts
function NcWaasProvider({ apiUrl, tenantId, appId, chain, config, core: suppliedCore, children }: NcWaasProviderProps): import("react").JSX.Element;
```

### NcWaasProviderProps

interface · react/provider.d.ts

```ts
interface NcWaasProviderProps {
    /** Pouchi API origin, for example `https://api.example.com`. */
    apiUrl: string;
    /** Pouchi tenant id. */
    tenantId?: string;
    /** Privy-compatible alias of `tenantId`, so `<PrivyProvider appId=...>` keeps working. */
    appId?: string;
    /** Accepted for Privy compatibility; not used. */
    clientId?: string;
    /** The tenant's chain. Falls back to `config.defaultChain`. */
    chain?: Chain;
    config?: NcWaasConfig;
    /** Advanced: supply a preconfigured controller (custom storage, tests). */
    core?: NcWaasCore;
    children?: ReactNode;
}
```

### NcWaasConfig

interface · types.d.ts

```ts
interface NcWaasConfig {
    loginMethods?: LoginMethod[];
    appearance?: NcWaasAppearance;
    /** Privy-compatible; external (Solana) wallet connectors are accepted and ignored. */
    externalWallets?: Record<string, unknown>;
    /** Privy-compatible Solana settings (`solana.rpcs`); Pouchi wallets are EVM only, so this is accepted and ignored. */
    solana?: Record<string, unknown>;
    /** Privy-compatible. Pouchi always creates the wallet at first login; the value is accepted and ignored. */
    embeddedWallets?: {
        ethereum?: {
            createOnLogin?: "users-without-wallets" | "all-users" | "off";
        };
        solana?: {
            createOnLogin?: "users-without-wallets" | "all-users" | "off";
        };
        createOnLogin?: "users-without-wallets" | "all-users" | "off";
        showWalletUIs?: boolean;
    };
    /** Privy-compatible chain config. The chain must equal the tenant's Pouchi chain. */
    defaultChain?: Chain;
    supportedChains?: Chain[];
    approvals?: {
        /**
         * Session approvals: approve once, then one-tap confirmations inside a capped, short-lived
         * policy. Requires a client registered by the tenant for this app. See useSessionApproval.
         */
        session?: SessionApprovalConfig;
    };
    /** Recovery backup methods offered at wallet setup and in recovery (spec §4.6). */
    backups?: {
        /** Google Drive app-data backup. Needs a Google OAuth web client ID for this app's origin (drive.appdata scope). */
        googleDrive?: {
            clientId: string;
            apiBase?: string;
            uploadBase?: string;
        };
    };
    mfa?: Record<string, unknown>;
    walletConnectCloudProjectId?: string;
    fundingMethodConfig?: Record<string, unknown>;
    intl?: Record<string, unknown>;
    legal?: {
        termsAndConditionsUrl?: string;
        privacyPolicyUrl?: string;
    };
    customAuth?: Record<string, unknown>;
    passkeys?: Record<string, unknown>;
    oauth?: {
        /**
         * The app page social login returns to. Default: the current page (origin + path). It must be registered
         * with Pouchi: an exact HTTPS URI in the tenant's OAuth redirect URIs (loopback pages on a registered
         * application origin also work outside production).
         */
        redirectUrl?: string;
    };
    transactions?: {
        /**
         * Optional tenant backend hook for contract calls. Without it, the signed-in user proposes
         * calls directly, limited by the tenant's userCallPolicy (registered contracts by default).
         */
        propose?: TransactionProposer;
        /** How long `sendTransaction` waits for an on-chain hash. Default 120 s. */
        timeoutMs?: number;
    };
}
```

### NcWaasAppearance

interface · types.d.ts

```ts
interface NcWaasAppearance {
    /**
     * "light", "dark", or "auto" (follows the OS, the default). Privy also accepts a hex background; it is treated as "auto".
     * Both palettes come from the same warm neutrals as the Pouchi web wallet.
     */
    theme?: "light" | "dark" | "auto" | `#${string}`;
    /**
     * Primary button, focus ring and selection color. Defaults to the near-black ink of the Pouchi look (no saturated
     * accent). The button text switches to black or white for contrast automatically.
     */
    accentColor?: `#${string}`;
    /**
     * Brand shown at the top left of every modal: an image URL or any React node (an inline SVG, a component). Without
     * it the header shows `appName` (default: the tenant name). Pass `appName` too so the image has an accessible name.
     */
    logo?: string | ReactNode;
    /** Title of the first login screen. Default: "이메일로 로그인" / "Log in with email". */
    landingHeader?: string;
    /** Subtitle of the first login screen. Default: "처음이면 지갑을 함께 만들어요. 비밀번호는 필요 없어요." */
    loginMessage?: string;
    /** Application name used in copy, as the logo's accessible name, and in local passkey prompts. */
    appName?: string;
    /**
     * Modal language: "ko" or "en", or the app's own language tag ("ko-KR" is Korean; any other language is English,
     * the sheets' only other language). Defaults to the browser language. Pass the app's current language here: when it
     * changes, the provider switches every sheet, including one that is open.
     */
    locale?: "ko" | "en" | (string & {});
    /** Hide the small platform attribution ("Powered by ...") under the login form. Default false. */
    hideAttribution?: boolean;
    /** Privy-compatible; Pouchi wallets are Ethereum only, so this is accepted and ignored. */
    walletChainType?: "ethereum-only" | "solana-only" | "ethereum-and-solana";
}
```

## Login and user

### usePrivy

function · react/hooks.d.ts

```ts
function usePrivy(): UsePrivyResult;
```

### UsePrivyResult

type · react/hooks.d.ts

```ts
type UsePrivyResult = UsePrivyCore & ReturnType<typeof useUnsupportedUnlinks> & ReturnType<typeof useUnsupportedLinks>;
```

### useLogin

function · react/hooks.d.ts

```ts
function useLogin(callbacks?: {
    onComplete?: (params: LoginCompleteParams) => void;
    onError?: (error: NcWaasError) => void;
}): {
    login: () => void;
};
```

### LoginCompleteParams

interface · react/hooks.d.ts

```ts
interface LoginCompleteParams {
    user: User;
    isNewUser: boolean;
    wasAlreadyAuthenticated: boolean;
    loginMethod: LoginMethodName | null;
    loginAccount: LinkedAccount | null;
}
```

### useLogout

function · react/hooks.d.ts

```ts
function useLogout(callbacks?: {
    onSuccess?: () => void;
}): {
    logout: () => Promise<void>;
};
```

### useLoginWithEmail

function · react/hooks.d.ts

Headless email login (Privy `useLoginWithEmail`). Drives the same flow as the modal; new
users still complete wallet protection and backup in the modal.

```ts
function useLoginWithEmail(callbacks?: {
    onComplete?: (params: LoginCompleteParams) => void;
    onError?: (error: NcWaasError) => void;
}): {
    sendCode: ({ email }: {
        email: string;
    }) => Promise<void>;
    loginWithCode: ({ code }: {
        code: string;
    }) => Promise<void>;
    state: {
        status: string;
        error: Error | null;
    };
};
```

### User

interface · types.d.ts

Privy-shaped user. `id` is stable per tenant wallet.

```ts
interface User {
    id: string;
    createdAt: Date;
    email?: {
        address: string;
    };
    /** Privy-compatible; Pouchi has no phone login. */
    phone?: {
        number: string;
    };
    wallet?: UserWallet;
    google?: UserOAuthAccount;
    apple?: UserOAuthAccount;
    kakao?: UserOAuthAccount;
    naver?: UserOAuthAccount;
    linkedAccounts: LinkedAccount[];
    mfaMethods: [];
    hasAcceptedTerms: boolean;
    isGuest: false;
    /** Pouchi specific. */
    ncWaas: {
        tenantId: string;
        walletId: string;
        status: AccountResponse["status"];
        deploymentStatus: AccountResponse["contract"]["deploymentStatus"];
    };
}
```

### UserWallet

interface · types.d.ts

```ts
interface UserWallet {
    address: Hex;
    /** Always "ethereum"; "solana" is in the type only so Privy code that branches on it compiles. */
    chainType: "ethereum" | "solana";
    chainId: string;
    /** "privy" is kept for drop-in compatibility with code that looks for the embedded wallet. */
    walletClientType: "privy" | (string & {});
    connectorType: "embedded" | (string & {});
    imported: boolean;
    delegated: boolean;
    walletIndex: number | null;
    recoveryMethod: "user-passcode" | (string & {});
    /** Pouchi specific. */
    walletId: string;
    /** Privy server-wallet id. Pouchi has no server wallets, so it is never set; use `walletId`. */
    id?: string | null;
}
```

## Social login, passkeys, linking

### useLoginWithOAuth

function · react/hooks.d.ts

Privy `useLoginWithOAuth`. `initOAuth({ provider })` leaves for the provider's sign-in and comes back to this
page (or `config.oauth.redirectUrl`); the provider finishes the login on load and calls `onComplete`.
Providers: those the tenant enabled among google, apple, kakao, naver.

```ts
function useLoginWithOAuth(callbacks?: {
    onComplete?: (params: LoginCompleteParams) => void;
    onError?: (error: NcWaasError) => void;
}): {
    state: OAuthFlowState;
    initOAuth: (input: {
        provider: OAuthProvider | PrivyOnlyOAuthProvider;
        disableSignup?: boolean;
    }) => Promise<void>;
    loading: boolean;
};
```

### useLinkAccount

function · react/hooks.d.ts

Privy `useLinkAccount`: link methods plus success and error callbacks (OAuth links finish after the redirect).

```ts
function useLinkAccount(callbacks?: {
    onSuccess?: (params: LinkAccountSuccess) => void;
    onError?: (error: NcWaasError, details: {
        linkMethod: LoginMethodName;
    }) => void;
}): {
    linkEmail: () => void;
    linkGoogle: () => void;
    linkApple: () => void;
    linkKakao: () => void;
    linkNaver: () => void;
    linkPhone: (..._args: unknown[]) => void;
    linkWallet: (..._args: unknown[]) => void;
    linkTwitter: (..._args: unknown[]) => void;
    linkDiscord: (..._args: unknown[]) => void;
    linkGithub: (..._args: unknown[]) => void;
    linkLinkedIn: (..._args: unknown[]) => void;
    linkTiktok: (..._args: unknown[]) => void;
    linkLine: (..._args: unknown[]) => void;
    linkSpotify: (..._args: unknown[]) => void;
    linkInstagram: (..._args: unknown[]) => void;
    linkFarcaster: (..._args: unknown[]) => void;
    linkTelegram: (..._args: unknown[]) => void;
    linkPasskey: () => void;
};
```

### LinkAccountSuccess

interface · react/hooks.d.ts

```ts
interface LinkAccountSuccess {
    user: User;
    linkMethod: LoginMethodName;
    linkedAccount: LinkedAccount | null;
}
```

### useLoginWithPasskey

function · react/hooks.d.ts

Privy `useLoginWithPasskey`: sign in with a passkey registered for this app (server-verified WebAuthn, discoverable
credential, no username). Register one with `useLinkAccount().linkPasskey()` while signed in.

```ts
function useLoginWithPasskey(callbacks?: {
    onComplete?: (params: LoginCompleteParams) => void;
    onError?: (error: NcWaasError) => void;
}): {
    loginWithPasskey: () => Promise<void>;
    state: {
        status: "initial" | "generating-challenge" | "done" | "error";
        error?: NcWaasError;
    };
};
```

### useSignupWithPasskey

function · react/hooks.d.ts

Privy `useSignupWithPasskey`. A Pouchi wallet needs an account identity (email or a social login) for recovery
notices, so passkey-only signup is refused; sign up with email or a social account and
add a passkey with `linkPasskey()`.

```ts
function useSignupWithPasskey(callbacks?: {
    onError?: (error: NcWaasError) => void;
}): {
    signupWithPasskey: () => Promise<never>;
    state: {
        status: "initial";
    };
};
```

## Wallets and transactions

### useWallets

function · react/hooks.d.ts

```ts
function useWallets(): {
    ready: boolean;
    wallets: ConnectedWallet[];
};
```

### ConnectedWallet

interface · react/hooks.d.ts

```ts
interface ConnectedWallet {
    address: Hex;
    /** Privy v3: the chain family. Pouchi wallets are always "ethereum" (EVM smart wallets); "solana" is in the type only so Privy code that branches on it compiles. */
    type: "ethereum" | "solana";
    walletIndex: 0;
    /** CAIP-2, for example `eip155:450815`. */
    chainId: string;
    walletClientType: "privy";
    connectorType: "embedded";
    imported: false;
    linked: true;
    meta: {
        name: string;
        id: string;
        icon?: string;
    };
    getEthereumProvider(): Promise<NcWaasEthereumProvider>;
    /** Privy alias of getEthereumProvider. Raw-hash signing (secp256k1_sign) is refused with 4200. */
    getProvider(): Promise<NcWaasEthereumProvider>;
    switchChain(chainId: number | `0x${string}`): Promise<void>;
    isConnected(): Promise<boolean>;
    disconnect(): void;
    /** Privy `wallet.sign(message)`: an ERC-1271 owner signature (WaaSWallet 4.1.0+). */
    sign(message: string): Promise<Hex>;
}
```

### getEthereumProviderFor

function · react/hooks.d.ts

One EIP-1193 provider per controller, shared by every wallet object.

```ts
function getEthereumProviderFor(core: NcWaasCore): NcWaasEthereumProvider;
```

### useSendTransaction

function · react/hooks.d.ts

```ts
function useSendTransaction(callbacks?: {
    onSuccess?: (result: {
        hash: Hex;
    }) => void;
    onError?: (error: NcWaasError) => void;
}): {
    sendTransaction: (input: UnsignedTransactionRequest, options?: SendTransactionOptions) => Promise<{
        hash: Hex;
    } & Omit<SendTransactionResult, "hash">>;
};
```

### SendTransactionOptions

interface · react/hooks.d.ts

```ts
interface SendTransactionOptions {
    /** Privy-compatible. Sponsorship follows the tenant policy; `false` is not honored yet. */
    sponsor?: boolean;
    uiOptions?: {
        header?: string;
        description?: string;
        buttonText?: string;
        showWalletUIs?: boolean;
    };
    address?: string;
}
```

### useSignMessage

function · react/hooks.d.ts

Privy `useSignMessage`: an ERC-1271 signature the wallet contract verifies
(`isValidSignature`, WaaSWallet 4.1.0+). The approval modal shows Pouchi's decoding of the
message (SIWE, plain text, or opaque data) and its risk flags before PIN or passkey.

```ts
function useSignMessage(callbacks?: {
    onSuccess?: (result: {
        signature: Hex;
    }) => void;
    onError?: (error: NcWaasError) => void;
}): {
    signMessage: (input: {
        message: string;
    }, _options?: unknown) => Promise<{
        signature: Hex;
    }>;
};
```

### useSignTypedData

function · react/hooks.d.ts

Privy `useSignTypedData` (EIP-712): permits, Permit2, marketplace orders. High-risk requests need an explicit confirmation.

```ts
function useSignTypedData(callbacks?: {
    onSuccess?: (result: {
        signature: Hex;
    }) => void;
    onError?: (error: NcWaasError) => void;
}): {
    signTypedData: (typedData: WaasTypedDataInput | string, _options?: unknown) => Promise<{
        signature: Hex;
    }>;
};
```

### useSendCalls

function · react/hooks.d.ts

Atomic batches (EIP-5792 `wallet_sendCalls`): one approval, executed together by the wallet contract; if one call
fails, none happen. Up to 8 calls. Returns the bundle id (for `getCallsStatus`) and the transaction hash.

```ts
function useSendCalls(callbacks?: {
    onSuccess?: (result: {
        id: string;
        hash: Hex;
    }) => void;
    onError?: (error: NcWaasError) => void;
}): {
    sendCalls: (input: {
        calls: UnsignedTransactionRequest[];
    }) => Promise<SendTransactionResult & {
        id: string;
    }>;
    getCallsStatus: (id: string) => Promise<import("../types").CallsStatus>;
};
```

### useSmartWallets

function · react/hooks.d.ts

Privy `useSmartWallets()` (`@privy-io/react-auth/smart-wallets`). The Pouchi wallet is itself an ERC-4337 smart
wallet, so `client.sendTransaction({ calls })` is an atomic batch and a single `{ to, value, data }` is a normal
transaction. Resolves to the transaction hash, as in Privy.

```ts
function useSmartWallets(): {
    client: {
        account: {
            address: `0x${string}`;
        };
        chain: import("viem").Chain;
        sendTransaction: (input: (UnsignedTransactionRequest | {
            calls: UnsignedTransactionRequest[];
        }) & {
            chain?: unknown;
            account?: unknown;
        }, _options?: unknown) => Promise<Hex>;
        signMessage: (input: {
            message: string;
        }) => Promise<`0x${string}`>;
        signTypedData: (typedData: WaasTypedDataInput | string) => Promise<`0x${string}`>;
    } | undefined;
    getClientForChain: ({ id }: {
        id: number;
    }) => Promise<{
        account: {
            address: `0x${string}`;
        };
        chain: import("viem").Chain;
        sendTransaction: (input: (UnsignedTransactionRequest | {
            calls: UnsignedTransactionRequest[];
        }) & {
            chain?: unknown;
            account?: unknown;
        }, _options?: unknown) => Promise<Hex>;
        signMessage: (input: {
            message: string;
        }) => Promise<`0x${string}`>;
        signTypedData: (typedData: WaasTypedDataInput | string) => Promise<`0x${string}`>;
    } | undefined>;
};
```

### TransactionProposer

type · types.d.ts

```ts
type TransactionProposer = (input: TransactionProposalInput) => Promise<{
    signingRequestId: string;
}>;
```

### TransactionProposalInput

interface · types.d.ts

Input passed to an optional tenant-backend transaction proposer. General contract calls use the configured proposer;
without it, the signed-in user may propose calls within the app's user-call policy.
Native and recognized supported-token transfers bypass this hook. See the server integration guide for the bounded example.

```ts
interface TransactionProposalInput {
    tenantId: string;
    walletId: string;
    walletAddress: Hex;
    chainId: number;
    to: Hex;
    value: string;
    data: Hex;
    /** App access token (ES256 JWT) for the backend to verify with `verifyAuthToken`. Never the Pouchi session. */
    accessToken: string;
}
```

### UnsignedTransactionRequest

interface · types.d.ts

```ts
interface UnsignedTransactionRequest {
    /** A 0x address. Privy types this as a plain string, so a string is accepted and checked at runtime. */
    to?: Hex | (string & {});
    from?: Hex;
    value?: bigint | number | string | Hex;
    data?: Hex;
    chainId?: number | Hex;
    gas?: bigint | number | string | Hex;
    gasLimit?: bigint | number | string | Hex;
    maxFeePerGas?: bigint | number | string | Hex;
    maxPriorityFeePerGas?: bigint | number | string | Hex;
    nonce?: number | Hex;
}
```

### SendTransactionResult

interface · types.d.ts

```ts
interface SendTransactionResult {
    hash: Hex;
    /** Pouchi specific: the ERC-4337 user operation hash and the API operation id. */
    userOperationHash?: Hex;
    operationId?: string;
    sponsored: boolean;
}
```

## Session approval

### useSessionApproval

function · react/hooks.d.ts

Approve once with PIN or passkey, then confirm transactions inside the session with one tap.
Requires `config.approvals.session`. The limits live in an owner-signed WaaSWallet policy,
so the contract enforces them whatever this UI does.

```ts
function useSessionApproval(): {
    session: import("../session-approvals").SessionApprovalState | null;
    active: boolean;
    startSession: (input: StartSessionInput) => Promise<import("../session-approvals").SessionApprovalState>;
    endSession: () => void;
};
```

### StartSessionInput

interface · session-approvals.d.ts

```ts
interface StartSessionInput {
    durationSeconds?: number;
    /** Total native value the session may move, decimal wei. "0" for calls without value. */
    maxTotalValueWei: string;
    /** Per-call native value cap, decimal wei. Defaults to the total. */
    maxValuePerCallWei?: string;
    maxCalls: number;
    contracts?: SessionPermissionInput[];
    /** Addresses that may receive plain native transfers. */
    nativeRecipients?: Hex[];
}
```

### SessionApprovalConfig

interface · session-approvals.d.ts

```ts
interface SessionApprovalConfig {
    /** Client registered by the tenant (`/v1/tenant/client-authorization-clients`, web channel). */
    clientId: string;
    clientName?: string;
    /** Must equal one of the client's registered webApprovalUris. Defaults to `${origin}/`. */
    approvalUri?: string;
    defaultDurationSeconds?: number;
}
```

### SessionApprovalState

interface · session-approvals.d.ts

```ts
interface SessionApprovalState {
    policyId: string;
    expiresAt: number;
    maxValuePerCallWei: string;
    valueAllowanceWei: string;
    spentWei: string;
    callsRemaining: number;
    permissions: SessionPermission[];
}
```

## Recovery and devices

### useWalletRecovery

function · react/hooks.d.ts

Moving the wallet to this device and watching recoveries.
`open()` shows the sheet: approve from the old device, or use the account recovery flow with a passkey or recovery code.

```ts
function useWalletRecovery(): {
    /** This device can sign; when false, `open()` moves the wallet here. */
    canSign: boolean;
    /** A recovery of this wallet that is waiting or running, on any device. */
    pending: import("../types").WalletRecoveryState | null;
    open: () => void;
    cancel: () => Promise<void>;
};
```

### useRecoverWallet

function · react/hooks.d.ts

Alias in Privy-style naming.

```ts
const useRecoverWallet: typeof useWalletRecovery;
```

### useRecoveryBackups

function · react/hooks.d.ts

Account recovery uses a passkey or recovery code, configured once in Pouchi Home. The API snapshot below retains legacy backup fields. Passkey entries carry only
ciphertext. App code never accesses key material; key-share operations stay inside the Pouchi vault frame.

```ts
function useRecoveryBackups(): {
    list: () => Promise<import("../core").RecoveryBackupSummary[]>;
    remove: (backupId: string) => Promise<void>;
    passkeySupported: () => Promise<boolean>;
    googleDriveAvailable: boolean;
};
```

### useSessions

function · react/devices.d.ts

The wallet's signed-in devices (spec §4.7). Each device keeps its own session; signing still needs that device's key
share and PIN or passkey. `revoke(deviceId)` signs another device out (it must sign in again).

```ts
function useSessions(options?: {
    auto?: boolean;
}): {
    devices: SignedInDevice[];
    maxDevices: number | null;
    loading: boolean;
    error: string | undefined;
    refresh: () => Promise<SignedInDevice[]>;
    revoke: (deviceId: string | null) => Promise<void>;
};
```

### useRevokeSession

function · react/devices.d.ts

Signs one other device out (Privy-style naming).

```ts
function useRevokeSession(): {
    revokeSession: (deviceId: string | null) => Promise<void>;
};
```

### LoggedInDevices

function · react/devices.d.ts

A small "signed-in devices" list for a settings screen, in the modal's look.

```ts
function LoggedInDevices({ theme }: {
    theme?: "light" | "dark" | "auto";
}): import("react").JSX.Element | null;
```

## Privy asset migration

### AssetMigrationCard

function · react/migration-card.d.ts

Minimal, unstyled-by-default card using the modal tokens; apps can build their own with the hook.

```ts
function AssetMigrationCard({ oldProvider, tokens }: {
    oldProvider: Eip1193Like | undefined;
    tokens?: MigrationToken[];
}): import("react").JSX.Element | null;
```

### useAssetMigration

function · react/migration-card.d.ts

Plans and runs the move from an old wallet (for example the Privy embedded wallet's
`getEthereumProvider()`) to the signed-in Pouchi wallet. The old wallet signs each step.

```ts
function useAssetMigration(options?: {
    tokens?: MigrationToken[];
}): {
    destination: `0x${string}` | undefined;
    plan: MigrationPlan | null;
    results: MigrationStepResult[];
    status: "error" | "done" | "ready" | "idle" | "planning" | "migrating";
    error: string | undefined;
    prepare: (oldProvider: Eip1193Like) => Promise<MigrationPlan>;
    migrate: (oldProvider: Eip1193Like) => Promise<MigrationStepResult[]>;
};
```

## Privy compatibility names (some reject)

Selected compatibility names for Privy migration. Check the support table and behavior differences first. Where the model differs, calls reject with `NOT_SUPPORTED` (EIP-1193 `4200`).

### useCreateWallet

function · react/privy-compat.d.ts

Privy `useCreateWallet`: the wallet already exists after first login; one wallet for the user in the current app context.

```ts
function useCreateWallet(callbacks?: {
    onSuccess?: (result: {
        wallet: UserWallet;
    }) => void;
    onError?: (error: NcWaasError) => void;
}): {
    createWallet: (options?: {
        createAdditional?: boolean;
        walletIndex?: number;
    }) => Promise<UserWallet>;
};
```

### useSolanaWallets

function · react/privy-compat.d.ts

Privy `useSolanaWallets`: Pouchi wallets are Ethereum (EVM) only.

```ts
function useSolanaWallets(): {
    ready: boolean;
    wallets: Array<{
        address: string;
        walletClientType: string;
        connectorType?: string;
        imported?: boolean;
    }>;
    createWallet: (..._args: unknown[]) => Promise<never>;
    exportWallet: (..._args: unknown[]) => Promise<never>;
};
```

### useSignTransaction

function · react/privy-compat.d.ts

Privy `useSignTransaction`: an ERC-4337 smart wallet has no raw signed transaction to return. Use
`useSendTransaction` (signs and submits a user operation) instead.

```ts
function useSignTransaction(callbacks?: {
    onError?: (error: NcWaasError) => void;
}): {
    signTransaction: (_input: UnsignedTransactionRequest, _options?: unknown) => Promise<string>;
};
```

### useFundWallet

function · react/privy-compat.d.ts

Privy `useFundWallet`: on-ramp and bridging are not part of Pouchi; fund the wallet address directly.

```ts
function useFundWallet(callbacks?: {
    onUserExited?: (params: unknown) => void;
}): {
    fundWallet: FundWallet;
};
```

### useCrossAppAccounts

function · react/privy-compat.d.ts

Privy `useCrossAppAccounts`.

```ts
function useCrossAppAccounts(): {
    linkCrossAppAccount: (_input: {
        appId: string;
    }) => Promise<never>;
    loginWithCrossAppAccount: (_input: {
        appId: string;
    }) => Promise<never>;
    sendTransaction: (..._args: unknown[]) => Promise<never>;
    signMessage: (..._args: unknown[]) => Promise<never>;
    signTypedData: (..._args: unknown[]) => Promise<never>;
};
```

### useSessionSigners

function · react/privy-compat.d.ts

Privy `useSessionSigners` (server-side delegated signing). Pouchi delegates through owner-signed, contract-
enforced policies instead: `useSessionApproval` for one-tap sessions, or agent permissions from the tenant backend.

```ts
function useSessionSigners(): {
    addSessionSigners: (_input: {
        address: string;
        signers: Array<{
            signerId: string;
            policyIds?: string[];
        }>;
    }) => Promise<never>;
    removeSessionSigners: (_input: {
        address: string;
    }) => Promise<never>;
};
```

### useImportWallet

function · react/privy-compat.d.ts

Privy `useImportWallet`: Pouchi never takes a raw private key; its key is generated 2-of-3 and never assembled.

```ts
function useImportWallet(): {
    importWallet: (_input: {
        privateKey: string;
    }) => Promise<never>;
};
```

### useMfaEnrollment

function · react/privy-compat.d.ts

Privy `useMfaEnrollment`: Pouchi approval uses user authentication (such as a passkey or PIN).

```ts
function useMfaEnrollment(): {
    initEnrollmentWithSms: (..._args: unknown[]) => Promise<never>;
    submitEnrollmentWithSms: (..._args: unknown[]) => Promise<never>;
    initEnrollmentWithTotp: (..._args: unknown[]) => Promise<never>;
    submitEnrollmentWithTotp: (..._args: unknown[]) => Promise<never>;
    initEnrollmentWithPasskey: (..._args: unknown[]) => Promise<never>;
    submitEnrollmentWithPasskey: (..._args: unknown[]) => Promise<never>;
    showMfaEnrollmentModal: () => never;
    closeMfaEnrollmentModal: () => undefined;
};
```

### useMfa

function · react/privy-compat.d.ts

Privy `useMfa` (no separate MFA step in Pouchi).

```ts
function useMfa(): {
    mfaMethods: string[];
    init: (..._args: unknown[]) => Promise<never>;
    submit: (..._args: unknown[]) => Promise<never>;
    cancel: () => undefined;
};
```

## Advanced: controller

### useNcWaas

function · react/provider.d.ts

The controller, for custom UIs (headless login and approval).

```ts
function useNcWaas(): NcWaasCore;
```

### useNcWaasState

function · react/provider.d.ts

The raw controller state. Prefer the Privy-compatible hooks for app code.

```ts
function useNcWaasState(): NcWaasState;
```

## Errors

### NcWaasError

class · errors.d.ts

```ts
class NcWaasError extends Error {
    readonly code: NcWaasErrorCode;
    /** EIP-1193 numeric code. Wallet libraries read this as `error.code` via `toRpcError`. */
    readonly rpcCode: number;
    /** Underlying API error code when the error came from the Pouchi API. */
    readonly apiCode?: string;
    readonly status?: number;
    readonly data?: unknown;
    constructor(code: NcWaasErrorCode, message: string, options?: {
        apiCode?: string;
        status?: number;
        data?: unknown;
        cause?: unknown;
    });
}
```

### NcWaasErrorCode

type · errors.d.ts

Errors surfaced by `@shard-lab/nc-waas-react`.

Every error carries a stable string `code` (for app logic) and, where it maps to
EIP-1193, a numeric `rpcCode` so wallet libraries such as viem and wagmi classify
it correctly (4001 user rejected, 4100 unauthorized, 4200 unsupported method,
4900 disconnected, 4901 chain disconnected).

```ts
type NcWaasErrorCode = "NOT_READY" | "NOT_AUTHENTICATED" | "USER_REJECTED" | "NOT_SUPPORTED" | "UNSUPPORTED_METHOD" | "UNSUPPORTED_CHAIN" | "INVALID_PARAMS" | "WALLET_NOT_READY" | "LOCAL_KEY_SHARE_MISSING" | "TRANSACTION_PROPOSER_REQUIRED" | "TRANSACTION_TIMEOUT" | "LOGIN_FLOW_INVALID" | "TOKEN_INVALID" | "UNSUPPORTED_CAPABILITY" | "API_ERROR";
```

## @shard-lab/nc-waas-react/server

Server only. Keep it out of browser bundles.

### createNcWaasServerClient

function · server.d.ts

Privy `new PrivyClient(...)` counterpart.

```ts
function createNcWaasServerClient(options: NcWaasServerOptions): NcWaasServerClient;
```

### NcWaasServerClient

class · server.d.ts

```ts
class NcWaasServerClient {
    constructor(options: NcWaasServerOptions);
    /**
     * Verifies an access token from `getAccessToken()` and returns who it belongs to.
     * JWTs are verified offline (signature, issuer, audience = this tenant's app, expiry).
     * Legacy session tokens fall back to introspection, which needs a credential.
     * Anything else throws `TOKEN_INVALID`.
     */
    verifyAuthToken(token: string): Promise<NcWaasAuthTokenClaims>;
    /** `@privy-io/node` shape: `privy.utils().auth().verifyAccessToken({ access_token })`. */
    utils(): {
        auth: () => {
            verifyAccessToken: ({ access_token }: {
                access_token: string;
            }) => Promise<NcWaasAuthTokenClaims>;
        };
    };
    /**
     * Creates the owner signing request for a contract call that the user then approves in the
     * browser. Optional: frontends can propose calls themselves within the tenant's policy.
     */
    proposeTransaction(input: ProposeTransactionInput): Promise<{
        signingRequestId: string;
    }>;
    /** The tenant's wallet by id (`wallets:read`): address, chain, status. No email or other login data. */
    getWallet(walletId: string): Promise<TenantWallet>;
    /** The tenant's user with this email login (`wallets:read`), or null. The match ignores case and surrounding spaces. */
    findUserByEmail(email: string): Promise<TenantUser | null>;
    /** The tenant's user with this wallet address (`wallets:read`), or null. */
    findUserByWalletAddress(address: string): Promise<TenantUser | null>;
}
```

### NcWaasServerOptions

interface · server.d.ts

```ts
interface NcWaasServerOptions {
    apiUrl: string;
    tenantId: string;
    /** Tenant Client Credential. Only for introspection, wallet reads and user lookups (`wallets:read`) and `proposeTransaction` (`owner-intents:create`). */
    credentialId?: string;
    clientSecret?: string;
    scopes?: Array<"wallets:read" | "owner-intents:create" | "user-intents:create" | "sponsorship:request">;
    /** Client Credential token audience. Defaults to the API origin. */
    audience?: string;
    /** Expected JWT issuer. Defaults to "urn:nc-waas". */
    issuer?: string;
    /** Defaults to `${apiUrl}/.well-known/jwks.json`. */
    jwksUrl?: string;
    /** Allowed clock skew. Default 30 s. */
    clockToleranceSeconds?: number;
    fetch?: typeof fetch;
    now?: () => number;
}
```

### NcWaasAuthTokenClaims

interface · server.d.ts

Verified claims. `userId` equals the browser `user.id`.

```ts
interface NcWaasAuthTokenClaims {
    appId: string;
    tenantId: string;
    tenantInstanceId?: string;
    userId: string;
    walletId: string;
    walletAddress: Hex;
    chainId: number;
    sessionId: string;
    issuer: string;
    /** Unix seconds. */
    issuedAt: number;
    /** Unix seconds. */
    expiration: number;
    authenticationMethod: string;
}
```

### ProposeTransactionInput

interface · server.d.ts

```ts
interface ProposeTransactionInput {
    walletId: string;
    to: Hex;
    value: string;
    data: Hex;
    title: string;
    description?: string;
    requester: {
        appName: string;
        origin: string;
    };
    risk?: "low" | "medium" | "high";
}
```

### linkPrivyUser

function · server.d.ts

Builds the user-id mapping record for a dual-login migration. Call it only after verifying
BOTH tokens in the same request: the Privy token with Privy's own verifier, the Pouchi
token with `verifyAuthToken`. Linking by email alone would let anyone who controls an
email claim another account. Store the record in your user table.

```ts
function linkPrivyUser(input: {
    privyClaims: {
        userId: string;
    };
    ncWaasClaims: NcWaasAuthTokenClaims;
    oldAddress?: string;
    now?: Date;
}): PrivyUserLink;
```

### PrivyUserLink

interface · server.d.ts

```ts
interface PrivyUserLink {
    privyUserId: string;
    ncWaasUserId: string;
    tenantId: string;
    walletId: string;
    oldAddress?: Hex;
    newAddress: Hex;
    linkedAt: string;
}
```

## @shard-lab/nc-waas-react/wagmi

### ncWaasConnector

function · wagmi.d.ts

```ts
function ncWaasConnector(options?: NcWaasConnectorOptions): (config: {
    emitter: WagmiConnectorEmitter;
}) => NcWaasWagmiConnector;
```

### NcWaasConnectorOptions

interface · wagmi.d.ts

```ts
interface NcWaasConnectorOptions {
    /** Defaults to the controller of the mounted provider. */
    core?: NcWaasCore;
    name?: string;
    icon?: string;
}
```
