import { C as CommitteeSigner } from './dvtWire-DxsrbfDe.cjs'; import { Address, Hex } from 'viem'; interface PasskeyRegistrationParams { email: string; username: string; password?: string; } interface PasskeyAuthenticationParams { email?: string; } interface TransactionVerificationParams { to: string; value?: string; data?: string; } interface PasskeyInfo { credentialId: string; publicKey: string; counter: number; deviceType: string; createdAt: string; } interface BeginRegistrationResponse { challenge: string; rp: { name: string; id: string; }; user: { id: string; name: string; displayName: string; }; pubKeyCredParams: any[]; timeout?: number; authenticatorSelection?: any; attestation?: string; } interface BeginAuthenticationResponse { challenge: string; timeout?: number; rpId?: string; allowCredentials?: any[]; userVerification?: string; } interface BeginTransactionVerificationResponse extends BeginAuthenticationResponse { userOpHash: string; } /** * Configurable backend routes for the passkey (WebAuthn) flows. * * These default paths are the standardized contract served by AAStar's * `@aastar/passkey-server` (any compatible RP exposing the same endpoints). * They are NOT specific to any single backend. Consumers pointing at a * different backend can override individual paths without changing code. */ interface PasskeyRoutes { /** POST — begin passkey registration. Default: `/auth/passkey/register/begin` */ registerBegin: string; /** POST — complete passkey registration. Default: `/auth/passkey/register/complete` */ registerComplete: string; /** POST — begin passkey login/authentication. Default: `/auth/passkey/login/begin` */ loginBegin: string; /** POST — complete passkey login/authentication. Default: `/auth/passkey/login/complete` */ loginComplete: string; /** POST — begin adding a new device (passkey). Default: `/auth/device/passkey/begin` */ deviceBegin: string; /** POST — complete adding a new device (passkey). Default: `/auth/device/passkey/complete` */ deviceComplete: string; /** POST — begin transaction verification. Default: `/auth/transaction/verify/begin` */ transactionVerifyBegin: string; } /** * Default passkey routes — the standardized `@aastar/passkey-server` contract. */ declare const DEFAULT_PASSKEY_ROUTES: PasskeyRoutes; declare class PasskeyManager { private api; private routes; constructor(baseURL: string, tokenProvider?: () => string | null, routes?: Partial); /** * Complete Passkey Registration Flow */ register(params: PasskeyRegistrationParams): Promise<{ user: any; token: string; passkey: PasskeyInfo; }>; /** * Complete Passkey Login/Authentication Flow */ authenticate(params?: PasskeyAuthenticationParams): Promise<{ user: any; token: string; }>; /** * Verify a transaction (Sign UserOpHash) with Passkey * Returns the verification credential needed for the transaction */ verifyTransaction(params: TransactionVerificationParams): Promise; /** * Add a new device (Passkey) to existing account */ addDevice(params: { email: string; password?: string; }): Promise; } interface BLSNode { index?: number; nodeId: string; nodeName: string; apiEndpoint: string; status: "active" | "inactive"; publicKey?: string; lastSeen?: Date; } interface BLSSignatureData { nodeIds: string[]; signatures?: string[]; publicKeys?: string[]; signature: string; messagePoint: string; aaAddress: string; aaSignature: string; messagePointSignature: string; aggregatedSignature?: string; } interface BLSConfig { seedNodes: string[]; discoveryTimeout?: number; } /** * Data for cumulative Tier 2 signature (algId 0x04): P256 + BLS. */ interface CumulativeT2SignatureData { p256Signature: string; /** Explicit bytes32 node IDs — LEGACY framing (`committeeActive() == false`). Mutually exclusive with {@link committeeSigners}. */ nodeIds?: string[]; blsSignature: string; /** * COMMITTEE framing (`committeeActive() == true`, CC-98/CC-103, FU-18): each signer carries its * `slot` + Merkle proof against the frozen committee set root. Mutually exclusive with {@link nodeIds}. */ committeeSigners?: readonly CommitteeSigner[]; /** Validator `TREE_DEPTH()`. Read it on-chain; defaults to 14 (`COMMITTEE_TREE_DEPTH_DEFAULT`) when `committeeSigners` is used. */ treeDepth?: number; } /** * Data for cumulative Tier 3 signature (algId 0x05): P256 + BLS + Guardian. */ interface CumulativeT3SignatureData extends CumulativeT2SignatureData { guardianSignature: string; } declare class BLSManager { private config; constructor(config: BLSConfig); /** * Discover available BLS nodes from seed nodes (Gossip network) */ getAvailableNodes(): Promise; /** * Helper to pack the full signature for ERC-4337 UserOp * Format: [nodeIdsLength][nodeIds...][blsSignature][messagePoint][aaSignature][messagePointSignature] */ packSignature(data: BLSSignatureData): string; /** * Calculate the MessagePoint G2 point for a given message (UserOpHash) */ generateMessagePoint(message: string | Uint8Array): Promise; /** * Pack cumulative Tier 2 signature (algId 0x04): P256 + BLS. * * Format: * [algId=0x04 (1)] [P256 r (32)] [P256 s (32)] * [nodeIdsLength (32)] [nodeIds (N×32)] * [blsAggregateSig (256)] [messagePoint (256)] * [messagePointECDSA (65)] */ packCumulativeT2Signature(data: CumulativeT2SignatureData): string; /** * Pack cumulative Tier 3 signature (algId 0x05): P256 + BLS + Guardian. * * Format: * [algId=0x05 (1)] [P256 r (32)] [P256 s (32)] * [nodeIdsLength (32)] [nodeIds (N×32)] * [blsAggregateSig (256)] [messagePoint (256)] * [messagePointECDSA (65)] [guardianECDSA (65)] */ packCumulativeT3Signature(data: CumulativeT3SignatureData): string; /** * @deprecated REMOVED behavior — do not use. This posted an untagged `{ message }` to `/signature/sign`, * which the DVT (YetAnotherAA-Validator v1.7+) no longer accepts: it now requires `{ userOp, ownerAuth }` * where `ownerAuth` is a TAG-prefixed owner authorization (0x01 ECDSA / 0x02 device-passkey) verified via * `account.isValidOwnerAuth` (#257/#261). There is no live caller. Sending `{ message }` to a v1.7+ node * fails owner-authorization, so this throws instead of silently hitting a rejection. Use the * TransferManager path (`_coordinateBlsAggregate` builds the tagged request via `buildDvtRequest`). */ requestNodeSignature(_node: BLSNode, _message: string): Promise<{ signature: string; publicKey: string; }>; /** * Request aggregation from a node */ aggregateSignatures(node: BLSNode, signatures: string[]): Promise; } interface AirAccountConfig { /** * Backend RP (relying party) API URL — required, no default. * * AAStar's official hosted RP will be `https://auth.aastar.io` (served by * aNode, see AAStarCommunity/YetAnotherAA-Validator#81). You can also point * this at your own backend implementing the standardized passkey contract * (see `@aastar/passkey-server` / {@link PasskeyRoutes}). */ apiURL: string; /** Function to get the current auth token (JWT) */ tokenProvider?: () => string | null; /** * Optional overrides for the passkey backend route paths. * * Defaults to the standardized `@aastar/passkey-server` contract * (`/auth/passkey/*`). Override individual paths to point at a backend that * exposes different routes without changing SDK code. */ passkeyRoutes?: Partial; /** BLS Configuration */ bls: BLSConfig; } declare class AirAccountClient { private config; readonly passkey: PasskeyManager; readonly bls: BLSManager; constructor(config: AirAccountConfig); } /** * @deprecated Renamed to {@link AirAccountConfig}. This alias is kept for * backward compatibility and will be removed in a future major version. */ type YAAAConfig = AirAccountConfig; /** * @deprecated Renamed to {@link AirAccountClient}. This alias is kept for * backward compatibility and will be removed in a future major version. */ declare const YAAAClient: typeof AirAccountClient; interface UserOperation { sender: string; nonce: bigint | string; initCode: string; callData: string; callGasLimit: bigint | string; verificationGasLimit: bigint | string; preVerificationGas: bigint | string; maxFeePerGas: bigint | string; maxPriorityFeePerGas: bigint | string; paymasterAndData: string; signature: string; } interface PackedUserOperation { sender: string; nonce: bigint | string; initCode: string; callData: string; accountGasLimits: string; preVerificationGas: bigint | string; gasFees: string; paymasterAndData: string; signature: string; } interface GasEstimate { callGasLimit: string; verificationGasLimit: string; preVerificationGas: string; } declare class ERC4337Utils { static packAccountGasLimits(verificationGasLimit: bigint | string, callGasLimit: bigint | string): string; static unpackAccountGasLimits(accountGasLimits: string): { verificationGasLimit: bigint; callGasLimit: bigint; }; static packGasFees(maxPriorityFeePerGas: bigint | string, maxFeePerGas: bigint | string): string; static unpackGasFees(gasFees: string): { maxPriorityFeePerGas: bigint; maxFeePerGas: bigint; }; static packUserOperation(userOp: any): PackedUserOperation; static unpackUserOperation(packedOp: PackedUserOperation): any; } declare class UserOpBuilder { private static DEFAULT_VERIFICATION_GAS_LIMIT; private static DEFAULT_PRE_VERIFICATION_GAS; private static DEFAULT_MAX_FEE_PER_GAS; private static DEFAULT_MAX_PRIORITY_FEE_PER_GAS; constructor(); /** * Build specific parts of a UserOperation * Note: Full construction often requires chain interaction (nonce, gas price), * which typically happens in the application layer or via a Provider wrapper. * This builder focuses on formatting and structure. */ buildUserOp(params: { sender: string; callData: string; nonce?: bigint; initCode?: string; callGasLimit?: bigint; verificationGasLimit?: bigint; preVerificationGas?: bigint; maxFeePerGas?: bigint; maxPriorityFeePerGas?: bigint; paymasterAndData?: string; signature?: string; }): Promise; /** * Hash the UserOperation for signing (ERC-4337 v0.7) */ getUserOpHash(userOp: PackedUserOperation, entryPoint: string, chainId: number): string; } declare const ALG_BLS = 1; declare const ALG_ECDSA = 2; declare const ALG_P256 = 3; declare const ALG_CUMULATIVE_T2 = 4; declare const ALG_CUMULATIVE_T3 = 5; declare const ALG_CUMULATIVE_T2_WA$1 = 9; declare const ALG_CUMULATIVE_T3_WA$1 = 10; type AlgId = typeof ALG_BLS | typeof ALG_ECDSA | typeof ALG_P256 | typeof ALG_CUMULATIVE_T2 | typeof ALG_CUMULATIVE_T3 | typeof ALG_CUMULATIVE_T2_WA$1 | typeof ALG_CUMULATIVE_T3_WA$1; type TierLevel = 1 | 2 | 3; interface TierConfig { /** Max value for Tier 1 (single ECDSA/Passkey). 0 = no enforcement. */ tier1Limit: bigint; /** Max value for Tier 2 (P256 + BLS). 0 = no enforcement. */ tier2Limit: bigint; } interface GuardStatus { hasGuard: boolean; guardAddress: string; dailyLimit: bigint; dailyRemaining: bigint; } interface PreCheckResult { ok: boolean; errors: string[]; tier: TierLevel; algId: AlgId; } /** * Determine the required tier for a given transaction value. * * - Tier 1: value <= tier1Limit — single ECDSA or P256 passkey * - Tier 2: tier1Limit < value <= tier2Limit — P256 + BLS aggregate * - Tier 3: value > tier2Limit — P256 + BLS + Guardian ECDSA * * If both limits are 0 (no enforcement), always returns Tier 1. */ declare function resolveTier(value: bigint, config: TierConfig): TierLevel; /** * Determine the required tier for an ERC-20 **token** transfer. This mirrors the on-chain GUARD * (`AAStarGlobalGuard.recordTokenSpend`), whose per-token semantics DIFFER from the account's * `requiredTier` at `tier2Limit == 0`: the guard treats a zero tier2Limit as an UNCAPPED Tier-2 * (`cfg.tier2Limit == 0 || cumulative <= cfg.tier2Limit` → T2), whereas the account (and * {@link resolveTier}) fall through to Tier-3. A valid token config may set `tier1Limit > 0, * tier2Limit == 0` (T1-capped, T2-uncapped; `_validateTokenConfig` only requires `daily >= tier1`). * Use this for the token path; use {@link resolveTier} for ETH/account-tier decisions. */ declare function resolveTokenTier(value: bigint, config: TierConfig): TierLevel; /** * Get the algorithm ID to use for a given tier. * * `webAuthn` selects the device-passkey (WebAuthn) cumulative variant for Tier-2/3 — the account * approves (and validateUserOp enforces) the EXACT signing algId, and the WebAuthn path signs * `0x09`/`0x0a`, NOT the raw-P256 `0x04`/`0x05`. A guard/pre-flight that queries the wrong algId gives a * false "algorithm not approved" on device-passkey accounts (#256). Tier-1 is always ECDSA `0x02` * (`useWebAuthnPasskey` applies to Tier-2/3 only — the device passkey is the composite P256 factor). * * - Tier 1: ALG_ECDSA (0x02) — single ECDSA, packed [0x02][r][s][v] (66 bytes); v0.25.0 requires the prefix (#273) * - Tier 2: raw ALG_CUMULATIVE_T2 (0x04) · WebAuthn ALG_CUMULATIVE_T2_WA (0x09) * - Tier 3: raw ALG_CUMULATIVE_T3 (0x05) · WebAuthn ALG_CUMULATIVE_T3_WA (0x0a) */ declare function algIdForTier(tier: TierLevel, webAuthn?: boolean): AlgId; /** * resolveTransfer — the unified "what does THIS transfer need?" decision API (aastar-sdk#176). * * A consumer (YAA) must not hand-judge the tier or read raw limits. It calls `resolveTransfer` once * and gets the branch: which tier, which signatures to collect (passkey / +BLS / +guardian), the * limits behind the decision, and any hard block. Works for ETH AND any ERC-20, because the two * INDEPENDENT on-chain mechanisms are combined here: * * 1. Tier (decides the SIGNATURES; Tier 3 = a guardian co-sign is REQUIRED). ETH uses the ACCOUNT * tier (`AAStarAirAccountV7.requiredTier` → resolveTier); an ERC-20 uses the GUARD's per-token * tier (`AAStarGlobalGuard.recordTokenSpend` → resolveTokenTier), which differs at tier2Limit==0 * (uncapped Tier-2, not Tier-3). Both evaluated against cumulative daily spend. * 2. Guard daily allowance (`AAStarGlobalGuard`): ETH `dailyLimit`/`remainingDailyAllowance`, or a * token's `tokenConfigs[token]` + `tokenTodaySpent`. This is a SEPARATE, HARD cap — * `Guard.recordSpend` reverts `DailyLimitExceeded` and a guardian does NOT bypass it. So * exceeding it is a `blockReason` (the transfer cannot succeed as-is), NOT a tier promotion. * * So `tier`/`requiredSigs` come from the account tier; `blockReason` flags a hard daily-limit block. * Read-only + browser-safe. * * NOTE on signatures: this returns what the on-chain `validateUserOp` will REQUIRE. Collecting them * (passkey assertion, DVT-BLS from the signer network, guardian ECDSA) + assembling the UserOp is the * prepare/submit flow's job; `resolveTransfer` is the planner that drives fail-fast (don't submit * until `requiredSigs` are all gathered). */ /** Signatures the chosen tier requires. */ interface RequiredSigs { /** Always true — the device passkey (P-256) signs every tier. */ passkey: true; /** Tier ≥ 2 needs the DVT-BLS aggregate signature. */ bls: boolean; /** Tier 3 needs this many guardian ECDSA co-signatures (1 for a normal T3 transfer). */ guardian: number; } /** The limits behind the decision (for the resolved asset). */ interface TransferLimits { tier1Limit: bigint; tier2Limit: bigint; dailyLimit: bigint; todaySpent: bigint; remaining: bigint; } interface TransferResolution { tier: TierLevel; requiredSigs: RequiredSigs; /** `'ETH'` for the native asset, else the ERC-20 token address. */ asset: 'ETH' | Address; limits: TransferLimits; /** * Whether AT LEAST ONE limit (tier1/tier2 or daily) is actually enforced for this asset. `false` * means nothing is enforced (no guard, or guard present but all limits 0, or an ERC-20 with no * tokenConfig) — so a `tier:1` result then reflects "unprotected", not "small amount". Computed the * same way for ETH and ERC-20. */ hasGuard: boolean; /** Why this tier was chosen (account-tier vs guard daily overage). */ reason: string; /** Set when the transfer is hard-blocked before signing (e.g. strict-mode unconfigured token). */ blockReason?: string; /** * Layer-1 on-chain policy preview (only when `policyRegistry` is passed). `willPass=false` means the * DVT signer will reject this transfer at the on-chain gate — warn the user before submitting. The * Layer-2 node gate + out-of-band confirmation are NOT previewed here (signer-side). */ policy?: { willPass: boolean; decision: number; limitValue: bigint; }; } /** Minimal read surface (decouples from viem's PublicClient generic). */ interface ReadClient$1 { readContract(args: { address: Address; abi: unknown; functionName: string; args?: readonly unknown[]; }): Promise; } /** Single source of truth for the tier → required-signatures mapping (weights: passkey≥T1, +BLS≥T2, +guardian≥T3). */ declare const sigsForTier: (t: TierLevel) => RequiredSigs; interface ResolveTransferParams { client: ReadClient$1; /** The AirAccount (smart account) address. */ account: Address; /** Transfer amount in the asset's base units (wei for ETH, token decimals for ERC-20). */ amount: bigint; /** ERC-20 token address; omit or `'ETH'` for the native asset. */ token?: Address | 'ETH'; /** Guard address; if omitted it's read from `account.guard()`. */ guard?: Address; /** * Layer-1 PolicyRegistry address. If given, the result includes a `policy` PREVIEW of the on-chain * per-account policy the DVT signer checks before signing (`checkPolicy`). NOTE: this previews only * Layer-1 (on-chain). The DVT node's Layer-2 env (operator allowlist / perTxMax) and out-of-band * confirmation are signer-side and surface in the signer's response, not here. */ policyRegistry?: Address; /** Transfer target (recipient/contract). REQUIRED for the policy preview — without it the preview * is skipped (previewing a self-transfer would give a misleading willPass=true). */ target?: Address; /** Call selector for the policy preview. Default: ETH `0x00000000`, ERC-20 `0xa9059cbb` (transfer). */ selector?: Hex; } declare function resolveTransfer(params: ResolveTransferParams): Promise; /** * Account tier PROFILES + tier-config encoders (aastar-sdk#176 phase 3). * * Both factory paths (`createAccount`, `createAccountWithDefaults`) leave the account's tier amount * thresholds (`tier1Limit`/`tier2Limit`) and weight config at 0 — so `requiredTier` stays 0 and the * weighted path reverts `WeightConfigNotInitialized`. The contract has a single `_buildDefaultConfig`, * so the per-user "profile → limits + weights" choice lives HERE, in the SDK (#176 补2/补3). After * `createAccountWithDefaults`, run {@link profileSetupCalls} (setTierLimits + setWeightConfig) to * actually arm the tiers — otherwise tiering is silently off (the #176 root cause). * * The encoders return an {@link AccountCall} (`{ to, value, data }`). IMPORTANT: `setTierLimits`, * `setWeightConfig`, `addGuardian` and `modifyTierLimitsWithGuardians` are all STRICT `onlyOwner` * (`msg.sender == owner`), NOT `onlyOwnerOrEntryPoint` — so they CANNOT be sent as a 4337 UserOp * (routing through the EntryPoint makes `msg.sender` the EntryPoint and reverts `NotOwner`), nor via * `account.execute` (that makes `msg.sender` the account). They must be a DIRECT tx FROM the owner key * (`{ to: account, data }`, `msg.sender == owner`). For a KMS/TEE-owned account the owner is a TEE-held * secp256k1 key, so the KMS signs + broadcasts the owner tx. RAISING limits later additionally needs * guardian co-signatures — see {@link encodeModifyTierLimitsWithGuardians}. Browser-safe (viem-only). */ /** A call the account OWNER sends as a DIRECT tx (`msg.sender == owner`) — NOT a UserOp/EntryPoint/ * `execute` (these targets are strict `onlyOwner` and would revert `NotOwner` otherwise). */ interface AccountCall { to: Address; value: bigint; data: Hex; } /** * The on-chain weight model: passkey=2, owner ECDSA=2, DVT-BLS=2, each guardian=1; tier thresholds * 3/5/6. Profiles vary the AMOUNT limits, not the weights. Exposed so callers can confirm/override. * * IMPORTANT (aastar-sdk#227): the contract's `_validateWeightConfig` REQUIRES every individual weight * to be STRICTLY LESS THAN tier1Threshold (`passkeyWeight >= tier1Threshold` reverts * `InsecureWeightConfig`). This is deliberate — no single factor may unlock any tier alone, so the * KMS-held owner ECDSA must always co-sign. So `passkeyWeight` is 2 (NOT 3): the product's "T1 = one * passkey" is a UX statement — a single WebAuthn gesture causes the KMS TEE to transparently emit BOTH * the P256 passkey sig (weight 2) AND the owner ECDSA sig (weight 2), summing to 4 >= tier1Threshold(3). * The on-chain account never sees a lone passkey. (The contract's AAStarAgentStorageLayout struct * comment still says "default: 3" — that is a stale contract-side doc bug, see airaccount-contract#146.) */ interface TierWeightConfig { passkeyWeight: number; ecdsaWeight: number; blsWeight: number; guardian0Weight: number; guardian1Weight: number; guardian2Weight: number; tier1Threshold: number; tier2Threshold: number; tier3Threshold: number; } declare const DEFAULT_WEIGHT_CONFIG: TierWeightConfig; type ProfileName = 'web3-newbie' | 'trader' | 'conservative'; interface AccountTierProfile { name: ProfileName; /** Up to this cumulative daily ETH spend → Tier 1 (passkey only). */ tier1Limit: bigint; /** Up to this → Tier 2 (passkey + BLS). Above it → Tier 3 (+ guardian). */ tier2Limit: bigint; /** Guard daily ETH allowance (a hard cap; set on the Guard, not the account tier). */ dailyLimit: bigint; weights: TierWeightConfig; } /** * Starting-point profiles (amounts in wei). These are SDK defaults — the UI shows them, lets the user * tweak, then arms the account with the chosen values. Override freely. */ declare const TIER_PROFILES: Record; /** `setTierLimits(tier1, tier2)` (onlyOwner) — arms the account tier amount thresholds. */ declare function encodeSetTierLimits(account: Address, tier1Limit: bigint, tier2Limit: bigint): AccountCall; /** `setWeightConfig(config)` (onlyOwner) — arms the weight thresholds (needed for the weighted path). */ declare function encodeSetWeightConfig(account: Address, weights?: TierWeightConfig): AccountCall; /** * The exact hash each guardian must sign to authorize a `modifyTierLimitsWithGuardians` change. * * Byte-identical to the account's `_guardianOpHash("MODIFY_TIER_LIMITS", abi.encode(nonce,t1,t2,deadline))` * (AAStarAirAccountBase.sol) — i.e. `keccak256(abi.encode(uint8 GUARDIAN_SIG_VERSION, chainId, account, * "MODIFY_TIER_LIMITS", opData))`. The contract recovers against `toEthSignedMessageHash(thisHash)`, so * each guardian signs the RETURNED hash as a raw message: * `walletClient.signMessage({ message: { raw: digest } })` (viem applies the EIP-191 prefix). * Collect RECOVERY_THRESHOLD (2) distinct guardian signatures, then pass them to * {@link encodeModifyTierLimitsWithGuardians}. * * `GUARDIAN_SIG_VERSION` is currently 4 (folded in to bind the account version/epoch); `tierLimitNonce` * must be the account's current `_tierLimitNonce` (needs a contract getter — see airaccount-contract). */ declare function modifyTierLimitsGuardianDigest(params: { chainId: bigint; account: Address; tierLimitNonce: bigint; tier1Limit: bigint; tier2Limit: bigint; deadline: bigint; /** Override only if the contract's GUARDIAN_SIG_VERSION changes (default 4). */ guardianSigVersion?: number; }): Hex; /** Minimal read surface (decouples from viem's PublicClient generic). */ interface ReadClient { readContract(args: { address: Address; abi: unknown; functionName: string; args?: readonly unknown[]; }): Promise; } /** * Read the account's current `tierLimitNonce()` from chain, then build the guardian challenge digest * for a `modifyTierLimitsWithGuardians` change — the one-call path that closes the #188 end-to-end gap * (the getter shipped in airaccount-contract#132). Equivalent to reading the nonce yourself and calling * {@link modifyTierLimitsGuardianDigest}. Guardians then sign the returned hash as a raw message. */ declare function modifyTierLimitsGuardianDigestFromChain(params: { client: ReadClient; account: Address; chainId: bigint; tier1Limit: bigint; tier2Limit: bigint; deadline: bigint; guardianSigVersion?: number; }): Promise; /** * RAISE the tier limits (guardian-gated) — `setTierLimits` only LOWERS without guardians; loosening * needs guardian co-signatures over the change (deadline-bound). Compute the per-guardian challenge * with {@link modifyTierLimitsGuardianDigest}, collect the signatures, then pass them here. */ declare function encodeModifyTierLimitsWithGuardians(account: Address, tier1Limit: bigint, tier2Limit: bigint, deadline: bigint, guardianSigs: Hex[]): AccountCall; /** * The calls to arm a freshly-created account with a profile: setTierLimits + setWeightConfig. Run * these right after `createAccountWithDefaults` (as owner) — WITHOUT them the account's tiers are off * (`requiredTier` returns 0) and large transfers revert for a missing tier (the #176 root cause). * The Guard `dailyLimit` is set separately at creation (`createAccountWithDefaults`'s dailyLimit arg). */ declare function profileSetupCalls(account: Address, profile: AccountTierProfile): AccountCall[]; /** * Out-of-band confirmation polling (aastar-sdk#176 phase 4 / #124). * * For a high-value op the DVT signer node WITHHOLDS its signature and sends the account's owner a * one-time token over an independent channel (Telegram today; email/Nostr later). The SDK's BLS * sign call surfaces this as a {@link DvtPendingConfirmationError} (with the node endpoint + * userOpHash). The user approves over their channel (NOT through the app — the app/attacker never * sees the token); the consumer then POLLS the node here until `approved`, and RE-SUBMITS the sign to * release the signature. * * Poll-only — it never calls `POST /signature/confirm` (that's the user's independent channel, by * design). Browser-safe (fetch). Transient errors during the poll do NOT end the (default 10-min) * window; the loop keeps trying until a terminal status, the timeout, or an abort. */ type ConfirmationStatus = 'pending' | 'approved' | 'expired' | 'not_found'; interface ConfirmationState { userOpHash: string; status: ConfirmationStatus; /** Epoch ms when the pending confirmation expires (null if not pending). */ expiresAt: number | null; } /** Read (does NOT consume) a node's out-of-band confirmation status: `GET /signature/confirmation/:userOpHash`. */ /** Combine an optional caller signal with a per-request timeout (a hung request must not stall). Shared * with the contact-binding client so a hung KMS read can't block the owner ceremony (#203 N3). */ declare function requestSignal(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal; declare function getDvtConfirmationStatus(nodeEndpoint: string, userOpHash: string, signal?: AbortSignal, requestTimeoutMs?: number): Promise; interface PollConfirmationOptions { /** Poll interval (ms). Default 3000. */ intervalMs?: number; /** Give up after this long (ms). Default 600_000 (the node's 10-min TTL). */ timeoutMs?: number; /** Abort the poll (also cancels the in-flight fetch + the sleep). */ signal?: AbortSignal; /** Called on each successful status read (for UI progress). */ onStatus?: (state: ConfirmationState) => void; /** Called on a transient read error (the poll keeps going until timeout — it does NOT end the window). */ onError?: (error: unknown) => void; /** Per-request fetch timeout (ms). A hung node read times out + retries, not stalls. Default 15000. */ requestTimeoutMs?: number; } /** * Poll a node until the out-of-band confirmation is `approved` (re-submit the sign then) or terminal * (`expired`/`not_found`) or the timeout elapses. A transient network/5xx error does NOT abort the * window — it's reported via `onError` and retried until the deadline (so a blip doesn't waste the * user's 10-min approval window). Aborts via `signal` (rejects with an AbortError). */ declare function pollDvtConfirmation(nodeEndpoint: string, userOpHash: string, options?: PollConfirmationOptions): Promise; /** * The WebAuthn assertion exactly as `navigator.credentials.get()` returns it (serialized by e.g. * `@simplewebauthn/browser`'s `startAuthentication`). It is POSTed to the DVT node AS-IS — do NOT * flatten to `{authenticatorData, clientDataJSON, signature}`: the KMS verifier needs `id`/`rawId`/ * `type` (the flat shape drops them and verification fails). */ interface AuthenticationResponseJSON { id: string; rawId: string; type: 'public-key'; response: { authenticatorData: string; clientDataJSON: string; signature: string; userHandle?: string; }; authenticatorAttachment?: string; clientExtensionResults?: Record; } /** * Build the `navigator.credentials.get({ publicKey })` request options for an out-of-band approval: * the WebAuthn challenge IS the 32-byte `userOpHash` (WYSIWYS — the user signs exactly the op they're * confirming). Run this in the browser, then pass the resulting assertion to {@link submitDvtConfirmation}. */ declare function confirmationCredentialRequest(userOpHash: string, opts: { rpId: string; allowCredentials?: { id: BufferSource; type?: 'public-key'; }[]; timeoutMs?: number; }): { challenge: Uint8Array; rpId: string; userVerification: 'required'; timeout?: number; allowCredentials?: { id: BufferSource; type: 'public-key'; }[]; }; /** * Submit an out-of-band approval to a DVT node: `POST {node}/signature/confirm { userOpHash, passkey }`. * `userOpHash` IS the pendingId; `passkey` is the {@link AuthenticationResponseJSON} passed AS-IS. The * node verifies the assertion (challenge==userOpHash + the account's passkey, delegated to the KMS) and * releases its withheld signature. Stateless + idempotent — the SAME assertion can be submitted to each * quorum node independently. */ declare function submitDvtConfirmation(nodeEndpoint: string, userOpHash: string, passkey: AuthenticationResponseJSON, signal?: AbortSignal): Promise<{ status: 'confirmed' | 'rejected'; confirmed: boolean; }>; /** * Browser-safe KMS contact-binding client (aastar-sdk#193 / AirAccount#129, KMS v0.27.0). * * Binds a notification channel (Telegram today; email pending KMS `begin_email_binding`) to an * AirAccount so the DVT out-of-band confirmation can reach the owner. Every begin/confirm/unbind is * gated by an OWNER WebAuthn ceremony (the app proves account ownership): the caller supplies a * `ceremony` that runs `POST /BeginAuthentication {KeyId}` → `navigator.credentials.get(challenge)` and * returns the assertion in the KMS's capitalized `{ChallengeId, Credential}` shape. * * Flow (Telegram, user-initiated — Telegram bots cannot DM a user who hasn't /started them): * 1. `beginContactBinding({account, channel})` → ceremony → `{bindingCode, expiresAt}`. * 2. The user sends `/bind ` to the official @AAStarBot; the bot claims it server-side * (NOT via this SDK) and delivers a `verifyToken` to the chat. * 3. The user enters that `verifyToken` in the app → `confirmContactBinding({account, bindingCode, * verifyToken})` → ceremony → `{status:'verified'}`. * 4. `getContacts(account)` lists verified channels; `removeContact({account, channel})` unbinds. * * fetch-based + browser-safe (no node:crypto). The approval side (out-of-band confirm) is a separate * passkey-over-userOpHash ceremony submitted to the DVT node — pending the DVT `/signature/confirm` * credential format (YetAnotherAA-Validator#124) — and is intentionally not in this module yet. */ type ContactChannel = 'telegram' | 'email'; /** A WebAuthn assertion in the KMS's capitalized wire shape (matches the existing KMS API). */ interface KmsWebAuthn { ChallengeId: string; Credential: unknown; } /** * Runs the owner WebAuthn ceremony and returns the KMS assertion. Provided by the app (browser): * `POST /BeginAuthentication {KeyId}` → `navigator.credentials.get(challenge)` → `{ChallengeId, Credential}`. * Receives the account so a multi-account app can pick the right passkey/key id. */ type OwnerCeremony = (ctx: { account: Address; purpose: 'begin-binding' | 'confirm-binding' | 'unbind'; }) => Promise; interface ContactBindingClientOptions { /** KMS base URL, e.g. `https://kms.aastar.io`. */ kmsEndpoint: string; /** KMS `x-api-key`. */ apiKey: string; /** Owner WebAuthn ceremony runner (see {@link OwnerCeremony}). */ ceremony: OwnerCeremony; /** Override fetch (tests / non-global-fetch runtimes). */ fetchImpl?: typeof fetch; /** Per-request timeout (ms) so a hung KMS request can't block the owner ceremony. Default 15000. (#203 N3) */ requestTimeoutMs?: number; } interface BeginBindingResult { bindingCode: string; expiresAt: number; } interface ContactRecord { channel: ContactChannel; /** The verified contact reference (e.g. Telegram chat id / email), as the KMS stores it. */ contactRef: string; status: 'pending' | 'verified' | 'revoked'; verifiedAt: number | null; } interface ContactBindingClient { beginContactBinding(p: { account: Address; channel: ContactChannel; }): Promise; confirmContactBinding(p: { account: Address; bindingCode: string; verifyToken: string; }): Promise<{ status: 'verified'; }>; getContacts(account: Address): Promise; removeContact(p: { account: Address; channel: ContactChannel; }): Promise<{ status: string; }>; } /** Create a browser-safe KMS contact-binding client bound to an endpoint + owner ceremony. */ declare function createContactBindingClient(options: ContactBindingClientOptions): ContactBindingClient; /** algId for a WebAuthn-passkey + BLS cumulative Tier-2 signature. */ declare const ALG_CUMULATIVE_T2_WA = 9; /** algId for a WebAuthn-passkey + BLS + Guardian cumulative Tier-3 signature. */ declare const ALG_CUMULATIVE_T3_WA = 10; /** * Build the WebAuthn assertion blob the contract decodes for the cumulative passkey factor: * abi.encode(bytes authenticatorData, bytes clientDataJSONPrefix, bytes clientDataJSONSuffix, * bytes32 r, bytes32 s) * * The signature is the raw P-256 DER from `navigator.credentials.get()`; r/s are decoded and the * low-S form is enforced (the contract rejects high-S). clientDataJSON is split into the fixed * `{"type":"webauthn.get","challenge":"` prefix and the suffix AFTER the base64url(challenge), so * the contract can reconstruct it around `base64url(userOpHash)`. * * @param assertion The three `AuthenticatorAssertionResponse` fields (ArrayBuffers decoded to bytes, * or hex; clientDataJSON may also be the raw JSON string). * @param userOpHash The op hash that MUST be the assertion's challenge — verified here so a mismatched * assertion fails in the SDK, not as an opaque on-chain revert. */ declare function packWebAuthnBlob(assertion: { authenticatorData: Hex | Uint8Array; clientDataJSON: Hex | Uint8Array | string; signature: Hex | Uint8Array; }, userOpHash: Hex): Hex; /** * Pack a WebAuthn cumulative Tier-2 signature (algId 0x09): * [0x09 (1)] [waBlobLen: uint32 BE (4)] [waBlob] [blsPayload] * where blsPayload = `[nodeIdsLength(32)][nodeIds(N×32)][blsSig(256)]` (build via {@link packBlsPayload}). */ declare function packCumulativeT2WA(waBlob: Hex, blsPayload: Hex): Hex; /** * Pack a WebAuthn cumulative Tier-3 signature (algId 0x0a): * [0x0a (1)] [waBlobLen: uint32 BE (4)] [waBlob] [blsPayload] [guardianECDSA (65)] */ declare function packCumulativeT3WA(waBlob: Hex, blsPayload: Hex, guardianSig: Hex): Hex; /** Build the LEGACY BLS payload block shared by the cumulative formats: `[nodeIdsLength(32)][nodeIds(N×32)][blsSig(256)]`. * nodeIds are sorted strictly ascending + dedup-checked before packing (#274). */ declare function packBlsPayload(nodeIds: readonly Hex[], blsSignature: Hex): Hex; /** * Build the COMMITTEE-framed BLS payload block (CC-103/FU-18) — the counterpart to * {@link packBlsPayload} for `committeeActive() == true`. Used directly by callers of the WebAuthn * cumulative packers ({@link packCumulativeT2WA}/{@link packCumulativeT3WA}, which take a pre-built * `blsPayload` and are framing-agnostic), and internally by {@link packCumulativeT2Signature}/ * {@link packCumulativeT3Signature} when `committeeSigners` is supplied. * * Thin wrapper over `@aastar/core`'s `encodeCommitteeBLSBlock` — kept here so this module has one * place for "the BLS payload block, either framing" rather than half living in `@aastar/core`. */ declare function packCommitteeBlsPayload(signers: readonly CommitteeSigner[], blsSignature: Hex, treeDepth?: number): Hex; export { ALG_BLS, ALG_CUMULATIVE_T2, ALG_CUMULATIVE_T2_WA, ALG_CUMULATIVE_T3, ALG_CUMULATIVE_T3_WA, ALG_ECDSA, ALG_P256, type AccountCall, type AccountTierProfile, AirAccountClient, type AirAccountConfig, type AlgId, type AuthenticationResponseJSON, type BLSConfig, BLSManager, type BLSNode, type BLSSignatureData, type BeginAuthenticationResponse, type BeginBindingResult, type BeginRegistrationResponse, type BeginTransactionVerificationResponse, type ConfirmationState, type ConfirmationStatus, type ContactBindingClient, type ContactBindingClientOptions, type ContactChannel, type ContactRecord, type CumulativeT2SignatureData, type CumulativeT3SignatureData, DEFAULT_PASSKEY_ROUTES, DEFAULT_WEIGHT_CONFIG, ERC4337Utils, type GasEstimate, type GuardStatus, type KmsWebAuthn, type OwnerCeremony, type PackedUserOperation, type PasskeyAuthenticationParams, type PasskeyInfo, PasskeyManager, type PasskeyRegistrationParams, type PasskeyRoutes, type PollConfirmationOptions, type PreCheckResult, type ProfileName, type RequiredSigs, type ResolveTransferParams, TIER_PROFILES, type TierConfig, type TierLevel, type TierWeightConfig, type TransactionVerificationParams, type TransferLimits, type TransferResolution, UserOpBuilder, type UserOperation, YAAAClient, type YAAAConfig, algIdForTier, confirmationCredentialRequest, createContactBindingClient, encodeModifyTierLimitsWithGuardians, encodeSetTierLimits, encodeSetWeightConfig, getDvtConfirmationStatus, modifyTierLimitsGuardianDigest, modifyTierLimitsGuardianDigestFromChain, packBlsPayload, packCommitteeBlsPayload, packCumulativeT2WA, packCumulativeT3WA, packWebAuthnBlob, pollDvtConfirmation, profileSetupCalls, requestSignal, resolveTier, resolveTokenTier, resolveTransfer, sigsForTier, submitDvtConfirmation };