import { z } from 'zod'; /** * In-process spend-intent cache so an identical send_token, swap_tokens, or * bridge_usdc retry does not broadcast a second settlement. * * Payment flow: reserve → execute → settle | release | hold-unknown. * Spend is counted at policy approve time. Definite not-charged outcomes * (quote, validation, confirmed uncharged revert, other pre-broadcast * failures) release that reservation and stay retryable. An unclear * post-broadcast outcome holds the reservation and locks the intent with * no timer — a later identical retry would otherwise double-settle. * * Keyless retries look up the settled payload (tool + tool-specific fields). * An explicit idempotencyKey is the lookup identity for that tool: the same * key with the same payload fingerprint replays, and the same key with a * different fingerprint fail-closes as a conflict instead of settling twice. * * A matching retry inside the TTL returns the original result and skips both * the spend-policy check and the on-chain transfer. x402_pay settles only * after a payment; an uncharged HTTP response is released and stays retryable. * * Keyed settled results stay until the durable LRU evicts them so the same * idempotencyKey replays after the keyless MCP-retry window. Keyless settled * results expire after SEND_TOKEN_INTENT_TTL_MS. Durable and unresolved maps * are size-capped so a long-lived process cannot grow them without bound. * * This is process-local, matching SpendingPolicy. It prevents duplicate * settlement from MCP tool retries; it is not a durable cross-process ledger. */ export declare const SEND_TOKEN_INTENT_TTL_MS: number; export declare const DEFAULT_SWAP_SLIPPAGE_BPS = 50; export declare const SPEND_INTENT_MAX_DURABLE = 1024; export declare const SPEND_INTENT_MAX_UNRESOLVED = 1024; /** * Published MCP JSON Schema for optional idempotencyKey on spend tools. * Runtime Zod applies the same minLength / maxLength / non-whitespace * pattern to the raw string (no trim-before-length). Identity lookup still * trims after validation. */ export declare const IDEMPOTENCY_KEY_JSON_SCHEMA: { type: "string"; minLength: number; maxLength: number; pattern: string; }; /** * Runtime check matching IDEMPOTENCY_KEY_JSON_SCHEMA: length and * non-whitespace apply to the raw string. Do not trim before min/max. */ export declare const IdempotencyKeyZodSchema: z.ZodString; export interface SpendIntentIdentity { key: string; fingerprint: string; } /** Policy/validation rejected the send before any transfer was broadcast. */ export declare class DefiniteSpendFailure extends Error { constructor(message: string); } /** * Payment already settled, but the follow-up HTTP response failed. * The intent must lock; the caller must not resubmit. */ export declare class PostSettlementSpendError extends Error { readonly txHash: string; readonly amount: string; readonly recipient: string; readonly cause: unknown; constructor(input: { txHash: string; amount: bigint | string; recipient: string; cause?: unknown; }); } /** * Run a pre-broadcast SDK phase (quote fetch, allowance read). Failures here * cannot have settled, so they stay retryable instead of locking the intent. */ export declare function runDefinitePreBroadcast(run: () => Promise): Promise; /** * Wrap SDK read methods so a failure inside swap()/bridge() is still * classified as definite. SwapModule.swap() calls this.getQuote() again; * BridgeModule.approveUsdc() re-reads allowance before any write. */ export declare function wrapDefiniteSdkReads(sdk: T): T; /** * BridgeModule.approveUsdc() inlines an allowance re-read before write. * Pre-check via getUsdcAllowance (already wrapped as definite). If allowance * is already sufficient, skip the original write path. Otherwise the original * re-read still runs; runClassifiedSpend treats a throw before write as * definite. */ export declare function classifyBridgeApproveUsdc(bridge: T): T; /** * Classify a value-moving SDK call. Errors before wallet write stay definite. * A confirmed uncharged revert (approve/burn/swap simulation or receipt * revert) also stays definite. Once a write is submitted and the outcome is * unclear, the error stays generic so the intent locks. * * Taxonomy comes from agentwallet-sdk `classifySpendError`. Wallet-write * instrumentation remains the fail-closed broadcast detector: the SDK * classifier treats unknown errors as released (pre-broadcast), which is * wrong after sendTransaction/writeContract has run. * * x402 sends the protocol fee before the merchant transfer. Pass * `lockAfterBroadcast: true` so a later revert cannot release the intent * and allow a second fee. */ export declare function runClassifiedSpend(walletClient: { sendTransaction?: unknown; writeContract?: unknown; } | null | undefined, run: () => Promise, options?: { lockAfterBroadcast?: boolean; }): Promise; /** Receipt-confirmed revert of an approve/burn/swap that did not move funds. */ export declare function isConfirmedUnchargedRevert(error: unknown): boolean; /** A prior attempt for this intent may already have broadcast a transfer. */ export declare class UnresolvedSpendIntentError extends Error { constructor(message: string); } /** The same idempotency key was reused with a different spend payload. */ export declare class SpendIntentConflictError extends Error { constructor(message: string); } /** * Require a complete EVM settlement hash before a spend callback may resolve * into the settled cache. A hashless or malformed SDK result is ambiguous — * the transfer may already have been broadcast — so this throws a generic * Error and the intent stays locked instead of replaying success:true with * a non-usable hash such as "pending" or "0x123". * * Canonical form is lowercase `0x` plus 64 hex chars. The SDK helper accepts * `0X`; that prefix is rejected here so cached hashes stay 0x-prefixed. */ export declare function requireSettlementHash(hash: unknown, label: string): string; export declare function sendTokenIntentIdentity(input: { chainId: number; tokenAddress: string; recipientAddress: string; rawAmount: bigint; idempotencyKey?: string; }): SpendIntentIdentity; export declare function sendTokenIntentKey(input: { chainId: number; tokenAddress: string; recipientAddress: string; rawAmount: bigint; idempotencyKey?: string; }): string; export declare function swapTokensIntentIdentity(input: { chainId: number; fromTokenAddress: string; toTokenAddress: string; rawAmountIn: bigint; slippageBps?: number; idempotencyKey?: string; }): SpendIntentIdentity; export declare function swapTokensIntentKey(input: { chainId: number; fromTokenAddress: string; toTokenAddress: string; rawAmountIn: bigint; slippageBps?: number; idempotencyKey?: string; }): string; export declare function bridgeUsdcIntentIdentity(input: { fromChain: string; toChain: string; rawAmount: bigint; idempotencyKey?: string; }): SpendIntentIdentity; export declare function bridgeUsdcIntentKey(input: { fromChain: string; toChain: string; rawAmount: bigint; idempotencyKey?: string; }): string; export declare function x402PayIntentIdentity(input: { url: string; method: string; body?: string; headers?: Record; idempotencyKey?: string; }): SpendIntentIdentity; export declare function x402PayIntentKey(input: { url: string; method: string; body?: string; headers?: Record; idempotencyKey?: string; }): string; export declare function _resetSpendIntentStore(): void; export declare function _spendIntentStoreSizes(): { ephemeral: number; durable: number; unresolved: number; }; export declare function withSpendIntent(key: string, run: () => Promise, options?: { durable?: boolean; fingerprint?: string; shouldSettle?: (_value: T) => boolean; }): Promise<{ value: T; replayed: boolean; }>; //# sourceMappingURL=spend-intent.d.ts.map