/** * WalletReservation — local accounting layer for concurrent paid tool calls. * * Problem this solves: when N batch tools (ImageGen / VideoGen) run in * parallel, each independently checks balance and dispatches its x402 * payment. With balance $0.20 and 6 calls × $0.04 each, all 6 see "$0.20 * available, $0.04 fits" and start; only 5 can actually settle on-chain, * the rest fail mid-flight with insufficient-funds and the user sees * partial completion with no preflight warning. * * The fix is *not* on-chain — x402 is fire-and-forget per-request, there's * no real "hold" capability. Instead this is a per-process bookkeeping * layer: * 1. Tool calls hold(amount) before paying. * 2. hold() refuses if (balance - sum(active reservations)) < amount. * 3. After payment succeeds OR fails, tool calls release(token). * * Single-process JS guarantees the check-and-set is atomic (no real race), * and balance is cached briefly so we don't hit the RPC for every hold. */ export interface ReservationToken { id: string; amountUsd: number; } declare class WalletReservationManager { private reserved; private cachedBalance; private balanceFetchInflight; private fetchBalance; private totalReserved; /** * Try to reserve `amountUsd`. Returns a token on success, or null if * insufficient (balance - already-reserved < amountUsd). Caller MUST * release the token after the actual payment resolves, success or fail. */ hold(amountUsd: number): Promise; /** * Release a hold. Idempotent — releasing the same token twice is a no-op. * Invalidate the balance cache so the next hold sees up-to-date state. */ release(token: ReservationToken | string | null | undefined): void; /** Force the next hold() to refetch balance from chain. */ invalidateBalance(): void; /** Snapshot of current reservation state — diagnostic / testing only. */ snapshot(): { count: number; totalUsd: number; }; } export declare const walletReservation: WalletReservationManager; export {};