import { TypedData, Call, InvocationsSignerDetails, SignerInterface } from 'starknet'; import * as _starkware_libs_starknet_privacy_sdk from '@starkware-libs/starknet-privacy-sdk'; /** * Identity for a Cavos wallet. Login (email / social / OTP) only ever produces a * stable `userId`; that's all the wallet needs to derive its address. Auth never * touches signing — the device key does that, silently. * * Privy-style UX: the user "logs in" and the wallet is provisioned behind the * scenes (device key + auto-deployed smart account). The app never handles keys. */ interface Identity { /** Stable, backend-managed user identifier. */ userId: string; /** Optional metadata (email, provider) for display only. */ email?: string; /** * Display name from the OAuth id_token (standard OIDC `name` claim). * Populated by Google sign-in; absent for email and Apple * (their tokens don't carry it). Optional on purpose — * consumers should fall back to `email` / `userId` when unset. */ name?: string; provider?: "google" | "apple" | "email" | "otp" | string; } /** * Authenticates a user and returns their stable identity. Implementations: * - `CavosAuth` (hosted, mirrors `@cavos/react`: Google/Apple/email/OTP via the * Cavos backend) — the default, Privy-like experience. * - any custom provider (the app already authenticated the user elsewhere). */ interface AuthProvider { authenticate(): Promise; /** * The provider id_token from the last login, if this provider has one. The * wallet registry authenticates the end user with it — Cavos decides who owns * an address, so a public app id is not enough. Kept in memory only; a * returning device that no longer has one falls back to its address cache. */ getAuthToken?(): string | null; } /** Trivial provider when the app already has the user's stable id. */ declare class StaticIdentity implements AuthProvider { private readonly identity; constructor(identity: Identity); authenticate(): Promise; } /** secp256r1 (P-256) public key of a device signer. */ interface DevicePublicKey { x: bigint; y: bigint; } /** * First-write claim of a derived address. Native Ed25519 addresses come from * the MasterDEK, not from this map. Cavos records the claim for billing and * so two first devices cannot publish two different accounts for one login. */ interface WalletRegistry { /** The user's existing wallet, or null if they don't have one yet. */ lookup(userId: string): Promise; /** * Claim the address this device derived. Insert-only: if another device got * there first, the returned address is THAT one. */ register(params: { userId: string; address: string; initialSigner: DevicePublicKey; }): Promise; /** Note an additional device signer for the user's wallet (after approval). */ addDevice?(params: { userId: string; address: string; signer: DevicePublicKey; }): Promise; /** Drop a device signer after it has been revoked on-chain. */ removeDevice?(params: { userId: string; address: string; signer: DevicePublicKey; }): Promise; } interface RegisterResult { /** The address that is now recorded — ours, or the winner's on a conflict. */ address: string; /** True when someone else had already claimed this identity's row. */ conflict: boolean; } interface RegisteredWallet { address: string; /** Public keys of the devices registered on this wallet (if tracked). */ devices?: DevicePublicKey[]; } /** Simple in-memory registry for demos / tests. */ declare class InMemoryWalletRegistry implements WalletRegistry { private wallets; lookup(userId: string): Promise; register(params: { userId: string; address: string; initialSigner: DevicePublicKey; }): Promise<{ address: string; conflict: boolean; }>; addDevice(params: { userId: string; address: string; signer: DevicePublicKey; }): Promise; removeDevice(params: { userId: string; address: string; signer: DevicePublicKey; }): Promise; } interface PasskeyEnrollParams { userId: string; userName: string; displayName?: string; } interface PasskeyPrfEnrollResult { credentialId: Uint8Array; secret?: Uint8Array; } /** Runtime-neutral PRF contract used by the Stellar envelope factor. */ interface PasskeyPrfProvider { enroll(params: PasskeyEnrollParams): Promise; getSecret(credentialId?: Uint8Array): Promise; } /** * A fresh provider token plus its non-secret fingerprint. The fingerprint is * sent to the control plane to reserve a single recovery session; the token * itself is sent only through the attested encrypted channel. */ type SocialRecoveryProvider$1 = "google" | "apple" | "email"; interface SocialRecoveryCredential { idToken: string; tokenFingerprint: string; /** * Which provider signed this token, read from its `iss`. * * The control plane needs it to pick the policy the enclave verifies * against, and cannot read it itself: the token only reaches the enclave, * encrypted, after the session already exists. Reading it here is not a * security check — the enclave verifies the signature, issuer and audience * against the sealed policy, and a wrong answer here produces a policy the * token cannot verify against rather than one that wrongly accepts it. */ provider: SocialRecoveryProvider$1; /** * The secret whose hash this login sent as the `nonce` (see * `auth/loginBinding`). The enclave requires it beside every token; it * travels only inside the job encrypted to the enclave. */ noncePreimage?: string; } declare function createSocialRecoveryCredential(idToken: string, noncePreimage?: string): SocialRecoveryCredential; /** * Verification of AWS Nitro Enclaves attestation documents. * * This answers one question for the browser: *is the key I am about to encrypt * my Google credential to actually held by the enclave image Cavos published?* * Nothing else in the recovery flow is load-bearing for confidentiality — the * control plane and the enclave's parent instance only ever relay ciphertext — * so this file is the security boundary and is written to be read closely. * * The trust anchor is the AWS Nitro root certificate, pinned below as bytes. It * ships in this package rather than arriving from the recovery API for the same * reason the workload measurements do: an API that told the client which root * to trust could name its own, and the attestation would prove nothing. * * Document format: RFC 8949 CBOR, signed as a COSE_Sign1 structure with ES384. * See https://docs.aws.amazon.com/enclaves/latest/user/verify-root.html */ /** * Which enclave the SDK is willing to talk to. * * `pcr0` accepts a list so an image rollout can overlap: publish the new * measurement alongside the one still deployed, ship the release, then * redeploy. Apps on either version keep working through the transition. * Order is newest first. */ interface NitroAttestationPolicy { /** Accepted PCR0 values (hex, no `0x`) — the measurement of the enclave image. */ pcr0: string | string[]; } type SocialRecoveryProvider = "google" | "apple" | "email"; type SocialRecoveryAction = "enroll" | "recover"; /** * Which enclave this build will talk to. See `attestationDefaults.ts`. */ type AttestationPolicy = NitroAttestationPolicy; interface SocialRecoveryClientOptions { baseUrl: string; appId: string; environment?: "development" | "production"; /** * Values pinned by the developer from the Cavos environment configuration. * They must not be learned from the same control plane being attested. */ attestation: AttestationPolicy; } interface ProviderPolicy { app_id: string; environment_id: string; provider: SocialRecoveryProvider; issuer: string; audience: string; jwks_uri: string; } type ChainAuthorization = { chain: "starknet"; chain_id_hex: string; account_hex: string; new_x_hex: string; new_y_hex: string; recovery_nonce: string; expires_at: number; } | { chain: "solana"; account_b58_bytes_b64: string; new_pubkey_b64: string; /** Decimal u64 string; JavaScript numbers cannot represent every nonce. */ recovery_nonce: string; expires_at: number; }; interface SocialRecoveryResult { result: "enrolled" | "recovered" | "confirmed"; [key: string]: unknown; } /** * Talks to the Cavos recovery enclave. * * The OIDC credential is encrypted in-browser to a P-256 key held only by an * AWS Nitro Enclave whose measurement this build pins. The Cavos API and the * enclave's parent instance relay ciphertext and are not trusted with any of it. * * Two round trips, both synchronous: start a session, then run the job. The * previous Confidential Space transport had to prewarm a VM before login and * then poll two endpoints for up to two minutes while it booted. */ declare class SocialRecoveryClient { private readonly opts; constructor(opts: SocialRecoveryClientOptions); lookupDekEnrollment(params: { provider: SocialRecoveryCredential["provider"]; subject: string; /** Proves the caller is `subject`; the answer names that person's wallet. */ idToken: string; }): Promise<{ wallet_address: string; } | null>; enroll(params: { walletAddress: string; credential: SocialRecoveryCredential; dek?: Uint8Array; }): Promise<{ sessionId: string; result: SocialRecoveryResult; }>; recover(params: { walletAddress: string; credential: SocialRecoveryCredential; authorizations?: ChainAuthorization[]; recipientPublicSec1?: Uint8Array; }): Promise<{ sessionId: string; result: SocialRecoveryResult; }>; confirmEnrollment(sessionId: string, txHash: string): Promise; private start; private runJob; private fetchJson; } declare const masterDekBrand: unique symbol; declare const ed25519SeedBrand: unique symbol; /** 32-byte account secret. Lives in the sealed record. Never a spend key by itself. */ type MasterDEK = Uint8Array & { readonly [masterDekBrand]: "MasterDEK"; }; /** 32-byte Ed25519 seed for one chain. HKDF of a MasterDEK. Import then zeroize. */ type Ed25519Seed = Uint8Array & { readonly [ed25519SeedBrand]: "Ed25519Seed"; }; declare const wrappedDekBrand: unique symbol; /** ECIES blob. ephPubCompressed(33) || nonce(12) || AES-GCM(DEK). */ type WrappedDEK = Uint8Array & { readonly [wrappedDekBrand]: "WrappedDEK"; }; interface DeviceFactor { publicKeySec1(): Uint8Array; unwrap(blob: WrappedDEK): Promise; wrap(dek: MasterDEK): WrappedDEK; } interface WrapStore { get(userId: string): Promise; put(userId: string, wrap: WrappedDEK): Promise; clear(userId: string): Promise; } interface EnclaveDekPort { lookupDek(params: { credential: SocialRecoveryCredential; }): Promise<{ address: string; } | null>; enrollDek(params: { address: string; credential: SocialRecoveryCredential; dek: MasterDEK; }): Promise<{ kind: "enrolled"; } | { kind: "already-enrolled"; address: string; }>; wrapDekToFactor(params: { address: string; credential: SocialRecoveryCredential; recipientSec1: Uint8Array; }): Promise; /** * Passkey path: the DEK is HKDF of the PRF, not a random secret stored on * the server. When this returns a DEK, ensure derives the address from it. */ mintDek?(params: { credential: SocialRecoveryCredential; }): Promise; /** * Restore the DEK of an account that already exists, from a factor that * holds a copy (a passkey). Ensure still checks it derives the address. */ restoreDek?(params: { credential: SocialRecoveryCredential; }): Promise; } /** * Signs whole Solana messages and prefixed off-chain messages, never raw * bytes, so a signer behind a policy can see what it is signing. */ interface Ed25519SpendSigner { address(): string; publicKeyRaw(): Uint8Array; signTransaction(message: Uint8Array): Promise; /** Signs `prefixedMessageBytes(message)`. */ signMessage(message: Uint8Array): Promise; } /** The chain reads a private operation needs. */ interface PrivacyChain { blockNumber(): Promise; call(contract: string, entrypoint: string, calldata?: string[]): Promise; /** Block the transaction landed in, or -1 when it reverted. */ confirm(transactionHash: string, options: PollOptions): Promise; } interface PollOptions { pollIntervalMs: number; timeoutMs: number; } type PrivacySdk = typeof _starkware_libs_starknet_privacy_sdk; type PrivacyRequirement = "register" | "setup-channel" | "setup-token" | "ready"; interface PrivacyStatus { /** The pool holds a viewing key for this account. */ registered: boolean; /** What the account still needs before it can use `token`. Only present when a token was asked about. */ requirement?: PrivacyRequirement; } interface PrivacySubmission { transactionHash: string; } /** The only operations a private account offers. No method returns a key, a note or a witness. */ interface PrivacyOperations { status(token?: string): Promise; balance(token: string): Promise; register(): Promise; deposit(token: string, amount: bigint): Promise; transfer(token: string, recipient: string, amount: bigint): Promise; withdraw(token: string, recipient: string, amount: bigint): Promise; } type Sdk = PrivacySdk; type CreateParams = Parameters[0]; /** Replaceable pieces, for tests that run against the SDK's in-memory pool. */ interface PrivacySessionDeps { chain?: PrivacyChain; sdk?: PrivacySdk; provingProvider?: CreateParams["provingProvider"]; discoveryProvider?: CreateParams["discoveryProvider"]; proofInvocationFactory?: CreateParams["proofInvocationFactory"]; fetch?: typeof fetch; poll?: PollOptions; } /** * The control-key signing capability used by CavosStellar. It signs whole * transactions, auth preimages and prefixed messages — never raw bytes — so a * signer that sits behind a policy can see what it is signing. */ interface ControlKey { /** Stellar `G…` address of the control public key. */ publicAddress(): string; /** The raw 32-byte Ed25519 public key. */ publicKeyRaw(): Uint8Array; signTransaction(xdr: string, networkPassphrase: string): Promise; signAuthEntry(preimageXdr: Uint8Array): Promise; /** Signs `prefixedMessageBytes(message)`. */ signMessage(message: Uint8Array): Promise; } /** A control key whose private half is in this process. */ declare abstract class LocalControlKey implements ControlKey { abstract publicAddress(): string; abstract publicKeyRaw(): Uint8Array; abstract sign(data: Uint8Array): Promise; signTransaction(xdr: string, networkPassphrase: string): Promise; signAuthEntry(preimageXdr: Uint8Array): Promise; signMessage(message: Uint8Array): Promise; } declare const VAULT_READY = "cavos-vault:ready"; declare const VAULT_HELLO = "cavos-vault:hello"; declare const POPUP_READY = "cavos-vault:popup-ready"; declare const POPUP_RESULT = "cavos-vault:popup-result"; type VaultChain = "solana" | "stellar" | "starknet"; type RecoveryMode = "enclave" | "passkey" | "none"; interface ConnectParams { chain: VaultChain; network: string; environment?: "development" | "production"; appSalt: string; userId: string; userName?: string; recovery: RecoveryMode; credential?: SocialRecoveryCredential; authToken?: string | null; } interface ConnectResult { handle: string; address: string; /** * Null when this browser holds no key for the account yet. Ed25519 raw bytes * on Solana and Stellar; the 32-byte stark public key on Starknet. */ publicKey: Uint8Array | null; isNewAccount: boolean; /** A passkey the user added can restore this account on a new device. */ passkey: boolean; } interface VaultMethods { connect(params: ConnectParams): ConnectResult; signSolanaTransaction(params: { handle: string; message: Uint8Array; }): Uint8Array; signStellarTransaction(params: { handle: string; xdr: string; networkPassphrase: string; }): Uint8Array; signStellarAuthEntry(params: { handle: string; preimage: Uint8Array; }): Uint8Array; signMessage(params: { handle: string; message: Uint8Array; }): Uint8Array; signStarknetTypedData(params: { handle: string; typedData: TypedData; accountAddress: string; }): string[]; signStarknetInvoke(params: { handle: string; calls: Call[]; details: InvocationsSignerDetails; }): string[]; /** The pool, prover, discovery and relay come from the app's Cavos settings. The page names none of them. */ privacyStatus(params: { handle: string; token?: string; }): PrivacyStatus; /** Decimal string of base units. Only the sum leaves the vault, never a note. */ privacyBalance(params: { handle: string; token: string; }): string; privacyRegister(params: { handle: string; paymasterApiKey: string; }): PrivacySubmission; privacyDeposit(params: { handle: string; token: string; amount: string; paymasterApiKey: string; }): PrivacySubmission; privacyTransfer(params: { handle: string; token: string; recipient: string; amount: string; paymasterApiKey: string; }): PrivacySubmission; privacyWithdraw(params: { handle: string; token: string; recipient: string; amount: string; paymasterApiKey: string; }): PrivacySubmission; forget(params: { userId: string; appSalt: string; }): void; /** Create a passkey that can restore the connected account on another device. */ enrollPasskey(params: { userId: string; appSalt: string; userName?: string; environment?: "development" | "production"; authToken?: string | null; }): void; } type VaultMethod = keyof VaultMethods; type VaultParams = Parameters[0]; type VaultResult = ReturnType; type VaultRequest = { [M in VaultMethod]: { id: number; method: M; params: VaultParams; }; }[VaultMethod]; type VaultReply = { id: number; ok: true; result: unknown; } | { id: number; ok: false; error: string; }; interface VaultEvent { event: "show" | "hide"; } /** The Cavos window is the fallback for passkeys some browsers refuse inside a cross-site frame. */ type PopupIntent = { kind: "passkey"; userId: string; userName: string; create: boolean; credentialId?: Uint8Array; }; type PopupResult = { secret: Uint8Array; credentialId?: Uint8Array; } | { error: string; }; declare const DEFAULT_VAULT_URL = "https://vault.cavos.xyz/vault"; interface VaultClientOptions { appId: string; url?: string; } /** * The app's side of the vault. Keys live in the vault's origin; this only * asks for signatures, and the vault decides whether to ask the user. */ declare class VaultClient { private readonly port; private static readonly attached; private nextId; private readonly pending; private constructor(); /** One iframe per vault URL and app, shared by every wallet on the page. */ static attach(opts: VaultClientOptions): VaultClient; /** Talk to a host over an existing port. For tests and custom transports. */ static fromPort(port: MessagePort): VaultClient; connectSolana(params: Omit): Promise<{ address: string; isNewAccount: boolean; spend: Ed25519SpendSigner | null; passkey: boolean; }>; connectStellar(params: Omit): Promise<{ address: string; isNewAccount: boolean; control?: ControlKey; passkey: boolean; }>; /** `paymasterApiKey` is what the vault hands the relay for private transfers. */ connectStarknet(params: Omit, paymasterApiKey?: string): Promise<{ address: string; isNewAccount: boolean; signer: SignerInterface | null; passkey: boolean; privacy: PrivacyOperations | null; }>; forget(userId: string, appSalt: string): Promise; /** Create a passkey, in the vault's own origin, that can restore the connected account on another device. */ enrollPasskey(params: VaultParams<"enrollPasskey">): Promise; private solanaSigner; private starknetPrivacy; private starknetSigner; private stellarSigner; private call; private settle; } export { type VaultReply as $, type AuthProvider as A, type ConnectResult as B, type ChainAuthorization as C, type DeviceFactor as D, type EnclaveDekPort as E, DEFAULT_VAULT_URL as F, POPUP_READY as G, POPUP_RESULT as H, type Identity as I, type PopupIntent as J, type PopupResult as K, LocalControlKey as L, type MasterDEK as M, type RecoveryMode as N, VAULT_HELLO as O, type PrivacyOperations as P, VAULT_READY as Q, type RegisteredWallet as R, type SocialRecoveryCredential as S, type VaultChain as T, type VaultClientOptions as U, VaultClient as V, type WalletRegistry as W, type VaultEvent as X, type VaultMethod as Y, type VaultMethods as Z, type VaultParams as _, SocialRecoveryClient as a, type VaultResult as a0, type WrapStore as b, type Ed25519Seed as c, type PasskeyPrfProvider as d, type PrivacySdk as e, type AttestationPolicy as f, type Ed25519SpendSigner as g, type PasskeyEnrollParams as h, type DevicePublicKey as i, type RegisterResult as j, InMemoryWalletRegistry as k, type PasskeyPrfEnrollResult as l, type PrivacyRequirement as m, type PrivacyStatus as n, type PrivacySubmission as o, type ProviderPolicy as p, type SocialRecoveryAction as q, type SocialRecoveryClientOptions as r, type SocialRecoveryProvider as s, type SocialRecoveryResult as t, StaticIdentity as u, createSocialRecoveryCredential as v, type ControlKey as w, type PrivacySessionDeps as x, type VaultRequest as y, type ConnectParams as z };