콘텐츠로 이동
요금문서EN

React SDK

@shard-lab/nc-waas-react(Pouchi Wallet React SDK)의 주요 Privy 호환 공개 API 선언 스냅샷입니다. 진입점은 .(React), ./server, ./wagmi, ./smart-wallets, ./solana, ./core(React 없음)입니다.

이름 하는 일 상태
PrivyProvider, NcWaasProvider 앱을 감싸는 Provider. apiUrl, appId(또는 tenantId), config.defaultChain(또는 chain) 지원
usePrivy ready, authenticated, user, login, logout, getAccessToken, signMessage, exportWallet(안내만), 계정 연결 지원
useLogin, useLogout 로그인 모달 열기와 완료, 로그아웃 콜백 지원
useLoginWithEmail 이메일 코드 로그인. 새 이용자는 Pouchi 화면에서 지갑 보호 설정 (sendCode, loginWithCode) 지원
useLoginWithOAuth google, apple, kakao, naver 로그인. 앱 운영자가 켜고 redirect URI를 등록해야 함 앱 설정 필요
useLinkAccount 이메일, 소셜, 패스키 연결. 다른 수단은 onError로 거절 지원
useLoginWithPasskey 등록된 패스키로 로그인 지원
useSignupWithPasskey 패스키만으로 가입 미지원 (거절)
useWallets 임베디드 스마트 지갑 1개와 EIP-1193 provider 지원
useSendTransaction 송금, ERC-20, 컨트랙트 호출. 승인 화면 뒤 { hash } 지원
useSignMessage, useSignTypedData ERC-1271 서명 (EIP-712 포함) 지원
useSendCalls, useSmartWallets 묶음 실행(EIP-5792, 최대 8개)과 Privy smart wallet 클라이언트 지원
useSessionApproval 앱 안 세션 키 위임. config.approvals.session.clientId 필요 지원
useWalletRecovery, useRecoverWallet 새 기기로 지갑 옮기기, 진행 중인 복구 보기 지원
useRecoveryBackups 백업 수단 목록과 삭제 지원
useSessions, useRevokeSession, LoggedInDevices 로그인한 기기 목록과 로그아웃시키기 지원
AssetMigrationCard, useAssetMigration Privy 옛 지갑에서 새 지갑으로 자산 옮기기 지원
useCreateWallet 첫 로그인 때 만든 지갑 돌려주기. 추가 지갑은 거절 부분 지원
useSessionSigners Privy 세션 서명자 미지원 (거절). useSessionApproval이나 서버 위임
useSignTransaction 원시 트랜잭션 서명 미지원 (거절). useSendTransaction
useFundWallet, useImportWallet, useCrossAppAccounts, useMfaEnrollment, useMfa, useSolanaWallets Privy 전용 기능 미지원 (거절 또는 빈 값)
useNcWaas, useNcWaasState 직접 화면을 만들 때 쓰는 컨트롤러와 상태 고급

function · react/provider.d.ts

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

const PrivyProvider: typeof NcWaasProvider;

function · react/provider.d.ts

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

interface · react/provider.d.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;
}

interface · types.d.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;
};
}

interface · types.d.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";
}

function · react/hooks.d.ts

function usePrivy(): UsePrivyResult;

type · react/hooks.d.ts

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

function · react/hooks.d.ts

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

interface · react/hooks.d.ts

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

function · react/hooks.d.ts

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

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.

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

interface · types.d.ts

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

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

interface · types.d.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;
}

소셜 로그인, 패스키, 계정 연결

섹션 제목: “소셜 로그인, 패스키, 계정 연결”

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.

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

function · react/hooks.d.ts

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

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

interface · react/hooks.d.ts

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

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.

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

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().

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

function · react/hooks.d.ts

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

interface · react/hooks.d.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>;
}

function · react/hooks.d.ts

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

function getEthereumProviderFor(core: NcWaasCore): NcWaasEthereumProvider;

function · react/hooks.d.ts

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

interface · react/hooks.d.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;
}

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.

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

function · react/hooks.d.ts

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

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

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.

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

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.

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

type · types.d.ts

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

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.

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

interface · types.d.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;
}

interface · types.d.ts

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

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.

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

interface · session-approvals.d.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[];
}

interface · session-approvals.d.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;
}

interface · session-approvals.d.ts

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

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.

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

function · react/hooks.d.ts

Alias in Privy-style naming.

const useRecoverWallet: typeof useWalletRecovery;

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.

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

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).

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

function · react/devices.d.ts

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

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

function · react/devices.d.ts

A small “signed-in devices” list for a settings screen, in the modal’s look.

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

function · react/migration-card.d.ts

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

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

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.

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 이전에 필요한 일부 호환 이름을 제공합니다. 지원 표와 다른 동작을 먼저 확인하세요. 모델이 다른 기능은 호출하면 NOT_SUPPORTED(EIP-1193 4200)로 거절합니다.

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.

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

function · react/privy-compat.d.ts

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

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

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.

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

function · react/privy-compat.d.ts

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

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

function · react/privy-compat.d.ts

Privy useCrossAppAccounts.

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

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.

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

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.

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

function · react/privy-compat.d.ts

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

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

function · react/privy-compat.d.ts

Privy useMfa (no separate MFA step in Pouchi).

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

function · react/provider.d.ts

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

function useNcWaas(): NcWaasCore;

function · react/provider.d.ts

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

function useNcWaasState(): NcWaasState;

class · errors.d.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;
});
}

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).

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

서버 전용입니다. 브라우저 번들에 넣지 않습니다.

function · server.d.ts

Privy new PrivyClient(...) counterpart.

function createNcWaasServerClient(options: NcWaasServerOptions): NcWaasServerClient;

class · server.d.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>;
}

interface · server.d.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;
}

interface · server.d.ts

Verified claims. userId equals the browser user.id.

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

interface · server.d.ts

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

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.

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

interface · server.d.ts

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

function · wagmi.d.ts

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

interface · wagmi.d.ts

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