import { f as InvoiceStatus, D as DeroChainId } from '../types-Bsy2LUTI.cjs'; import { X as X402ChallengeResponse } from '../x402-Czf0DzVv.cjs'; import { W as WalletRpcClient } from '../wallet-rpc-sY1qJ24S.cjs'; import { e as XSWDPayClient } from '../xswd-pay-x8P1qqAk.cjs'; import { I as InvoiceEngine } from '../invoice-engine-BzpQXq7Y.cjs'; import '../types-D-riGgKJ.cjs'; import '../rpc/index.cjs'; import '../manager-CNcr_RGt.cjs'; /** * Spending policy for autonomous x402 payments. * * Deny-by-default: an empty `allowOrigins` list authorizes nothing. * Reservations (not post-hoc records) enforce caps, so two concurrent * payments cannot both slip under a nearly-exhausted window cap: * reserve → pay → commit, or reserve → failure → release. */ type SpendPolicyConfig = { /** * Origins the payer may spend at, e.g. "https://api.example.com". * Compared against `new URL(target).origin`. Empty list denies everything. */ allowOrigins: string[]; /** Hard ceiling for a single payment, in atomic units. */ maxAtomicPerRequest: bigint; /** Optional rolling-window ceiling across payments. */ maxAtomicPerWindow?: { amountAtomic: bigint; windowSeconds: number; }; /** Injectable clock (ms since epoch) for tests. */ now?: () => number; }; type SpendDenialCode = "origin_not_allowed" | "over_per_request_cap" | "over_window_cap" | "invalid_amount"; declare class SpendPolicyError extends Error { readonly code: SpendDenialCode; readonly origin: string; readonly amountAtomic: bigint; constructor(code: SpendDenialCode, message: string, origin: string, amountAtomic: bigint); } type SpendReservation = { /** Finalize the reservation; the amount stays counted for the window. */ commit(): void; /** Cancel the reservation; the amount no longer counts against caps. */ release(): void; }; /** Optional context a guard may use to make a decision (e.g. resource-scoping). */ type SpendContext = { resource?: string; }; /** * The contract the paying agents depend on. Both SpendPolicy (origin + * amount caps) and CredentialPolicy (attenuable capabilities) implement * it, so either can be handed to createPayingFetch / createPayingToolCaller. */ interface SpendGuard { reserve(origin: string, amountAtomic: bigint, context?: SpendContext): SpendReservation; } declare class SpendPolicy { private readonly allowedOrigins; private readonly maxAtomicPerRequest; private readonly window?; private readonly now; private readonly ledger; constructor(config: SpendPolicyConfig); /** Sum of reserved + committed spend inside the current window. */ spentInWindow(): bigint; /** * Reserve spending authority for one payment. Throws SpendPolicyError * when any rule denies it. Callers MUST commit() after the payment * succeeds or release() after it fails. */ reserve(targetOrigin: string, amountAtomic: bigint): SpendReservation; private prune; } /** * Attenuable spending credentials — macaroon-style capabilities for * delegating a bounded slice of an agent's spending authority. * * A coordinating agent mints a credential from a root key with caveats * (max total spend, allowed origin, resource prefix, expiry). It hands * the credential to a worker/sub-agent, which can *attenuate* it — append * further caveats that only narrow authority — WITHOUT the root key. The * paying agent verifies the HMAC chain against the root key and enforces * every caveat locally before any transfer. * * This is the DERO analogue of L402's macaroon attenuation (NDSS 2014): * "a holder can add restrictions to an existing credential without * contacting the issuer." The key never leaves the issuer; a leaked * sub-credential can only ever be weaker than its parent. * * HMAC chain (identical construction to macaroons): * sig_0 = HMAC(rootKey, id) * sig_n = HMAC(sig_{n-1}, caveat_n) * The final signature authenticates the id + full ordered caveat list. * Appending a caveat is cheap and keyless; forging or reordering is not. */ type SpendCaveat = { type: "max-spend-atomic"; value: string; } | { type: "origin"; value: string; } | { type: "resource-prefix"; value: string; } | { type: "expires-at"; value: string; }; type SpendCredential = { /** Opaque credential id — also the first link of the HMAC chain. */ id: string; caveats: SpendCaveat[]; /** Hex HMAC over id + ordered caveats. */ signature: string; }; /** Mint a credential from the root key. Requires the secret. */ declare function mintSpendCredential(params: { rootKeyHex: string; id: string; caveats: SpendCaveat[]; }): SpendCredential; /** * Attenuate a credential by appending a caveat. Keyless: it extends the * HMAC chain from the current signature. The result is strictly weaker. */ declare function attenuate(cred: SpendCredential, caveat: SpendCaveat): SpendCredential; /** Verify the HMAC chain against the root key. Does NOT check caveats. */ declare function verifyCredentialSignature(cred: SpendCredential, rootKeyHex: string): boolean; type CredentialDenialCode = "bad_signature" | "expired" | "origin_not_allowed" | "resource_not_allowed" | "over_credential_cap" | "invalid_amount" | "malformed_caveat"; declare class CredentialError extends Error { readonly code: CredentialDenialCode; constructor(code: CredentialDenialCode, message: string); } /** * A spending guard backed by a verified credential. Implements the same * reserve()/commit()/release() contract as SpendPolicy, so it drops into * createPayingFetch / createPayingToolCaller interchangeably. * * The most restrictive caveat of each kind wins (attenuation can only * narrow): the effective cap is the minimum of all max-spend-atomic * caveats, the effective expiry the earliest, etc. Multiple origin or * resource-prefix caveats must ALL be satisfied. */ declare class CredentialPolicy { private readonly cap; private readonly origins; private readonly resourcePrefixes; private readonly expiry; private readonly now; private readonly ledger; constructor(cred: SpendCredential, rootKeyHex: string, opts?: { now?: () => number; }); /** Total reserved + committed spend under this credential. */ spent(): bigint; reserve(targetOrigin: string, amountAtomic: bigint, context?: { resource?: string; }): SpendReservation; } /** * Parsing for the wire shapes an autonomous payer consumes: the * x402-deropay-draft challenge emitted by `createX402RouteGuard` (HTTP * 402 body) and the serialized invoice served by `createPaymentHandlers`' * status endpoint. Validation is hand-rolled — dero-pay ships with zero * runtime dependencies, and these are two fixed shapes. */ /** * The challenge an agent pays. Structurally identical to the route * guard's 402 body; `settling` is added by MCP paid-tool challenges * while a referenced invoice waits for confirmations. */ type X402Challenge = X402ChallengeResponse & { settling?: boolean; }; /** What the agent needs from a serialized invoice status response. */ type InvoiceStatusSnapshot = { id: string; status: InvoiceStatus; amountAtomic: bigint; amountReceivedAtomic: bigint; expiresAt: string; }; /** * Parse an x402-deropay-draft challenge body. Returns null when the * value is not a well-formed challenge — the caller decides whether * that means "unpayable" or "pass the response through". */ declare function parseX402Challenge(body: unknown): X402Challenge | null; /** * Parse the JSON served by `GET /api/pay/status?invoiceId=` (a * serialized Invoice: bigints arrive as decimal strings). Returns null * on anything malformed so a flaky endpoint reads as "still waiting", * never as a bogus status. */ declare function parseInvoiceStatusResponse(json: unknown): InvoiceStatusSnapshot | null; /** * The payment primitive of the invoice rail: move DERO to a challenge's * integrated address and report the txid. Everything else — spend * policy, status polling, receipt redemption — lives in the flow layers * (createPayingFetch, createPayingToolCaller), so a payer stays a thin * wallet adapter. */ /** One invoice to pay, lifted from a parsed x402 challenge. */ type InvoicePayment = { invoiceId: string; /** Destination carrying the invoice's payment ID. A plain transfer here is the payment. */ integratedAddress: string; amountAtomic: bigint; network: DeroChainId; resource: string; expiresAt: string; }; /** Pays one invoice. Throwing means no DERO left the wallet. */ type InvoicePayer = (payment: InvoicePayment) => Promise<{ txid: string; }>; /** * Wallet-RPC payer: an InvoicePayer backed by the local DERO wallet's * JSON-RPC interface. This is the autonomous path — no human approval * per payment — so it is loopback-only by default: the wallet an agent * can drain must be yours. */ type WalletRpcPayerConfig = { /** Wallet RPC endpoint. Default: http://127.0.0.1:10103/json_rpc */ url?: string; /** * Pre-built client (tests / advanced wiring). Bypasses the loopback * check — the caller owns the endpoint's trust decision. */ client?: WalletRpcClient; /** * Allow a non-loopback wallet URL. Off by default: an autonomous payer * pointed at a remote wallet is a key-exfiltration hazard. */ allowNonLoopback?: boolean; /** Ring size for payment transfers. Default 16. */ ringsize?: number; }; declare function isLoopbackUrl(value: string): boolean; /** * Build an InvoicePayer that pays challenges through the local wallet: * a plain transfer to the invoice's integrated address, whose embedded * payment ID is what the merchant's PaymentMonitor matches on. */ declare function createWalletRpcPayer(config?: WalletRpcPayerConfig): InvoicePayer; /** * XSWD payer: an InvoicePayer that routes each payment through an XSWD * session, so the wallet owner approves every transfer in their wallet * UI. The human-in-the-loop counterpart to the wallet-RPC payer. */ declare function createXswdPayer(client: XSWDPayClient): InvoicePayer; /** * createPayingFetch — the autonomous agent payer for DeroPay's invoice/ * receipt rail. * * Wraps fetch: when a request comes back 402 with an x402-deropay-draft * challenge, it checks the spending policy, pays the invoice's * integrated address through the supplied InvoicePayer, polls the * merchant's payment API until the invoice completes, redeems it for a * DPAY-RECEIPT token, and retries the request with the receipt attached. * Every payment produces an evidence record; every denial is loud * (throws), because an autonomous agent silently proceeding unpaid — or * paying outside policy — is exactly what this layer exists to prevent. */ /** Record of one settled payment, for audit sinks. */ type PaymentEvidence = { at: string; origin: string; resource: string; network: DeroChainId; invoiceId: string; integratedAddress: string; amountAtomic: string; txid: string; /** Unset for MCP payments until the guard mints the receipt server-side. */ receiptJti?: string; receiptExpiresAt?: number; }; /** The 402 (or a broken issue step) received AFTER the invoice was paid. */ declare class X402PaymentRejectedError extends Error { readonly response: Response; readonly txid: string; readonly invoiceId: string; constructor(message: string, response: Response, txid: string, invoiceId: string); } /** A 402 that cannot be paid on this rail (wrong shape, protocol, or network). */ declare class X402UnpayableError extends Error { readonly response: Response; constructor(message: string, response: Response); } /** * The invoice was paid but did not complete inside the settlement * window. `reason: "deadline"` is recoverable — a later call through the * same payer resumes waiting on this invoice instead of paying again. * `reason: "invoice_expired"` is terminal: the transfer left the wallet * but the invoice lapsed; the carried fields identify what to reconcile. */ declare class X402SettlementTimeoutError extends Error { readonly reason: "deadline" | "invoice_expired"; readonly origin: string; readonly resource: string; readonly invoiceId: string; readonly txid: string; readonly integratedAddress: string; readonly paymentApi: string; constructor(message: string, reason: "deadline" | "invoice_expired", details: { origin: string; resource: string; invoiceId: string; txid: string; integratedAddress: string; paymentApi: string; }); } type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise; type PayingFetchConfig = { payer: InvoicePayer; policy: SpendGuard; /** Underlying fetch (tests / custom transport). Default: globalThis.fetch */ fetch?: FetchLike; /** * Where the merchant mounts createPaymentHandlers (status + receipt * issue endpoints). The challenge does not carry this, so it is a * convention: default `${origin}/api/pay` on the resource's origin. */ paymentApi?: string | ((challenge: X402Challenge, resourceUrl: string) => string); /** Challenge protocol this payer honors. Default "x402-deropay-draft". */ protocol?: string; /** Refuse challenges on any other network. Unset: pay whatever network the challenge names. */ network?: DeroChainId; /** Called after each payment settles into a receipt, with its evidence record. */ onPayment?: (evidence: PaymentEvidence) => void; /** * When a 402 cannot be paid on this rail: "passthrough" returns the 402 * response untouched; "throw" raises X402UnpayableError. Default "throw" * so agent code cannot mistake an unpaid body for a paid one. */ unpayable?: "throw" | "passthrough"; /** * How long to wait for the paid invoice to complete (tx mined + the * server's confirmation depth). Default 180s — mainnet needs ~18s per * confirmation. The SAME invoice is polled; a second payment is never made. */ settleTimeoutMs?: number; /** Delay between status polls. Default 2.5s. */ settlePollIntervalMs?: number; /** * Cache issued receipts per (origin, path) and attach them to later * requests until they expire, so repeat calls don't re-pay. Default * true. Disable against servers that enforce single-use receipts to * skip a wasted round-trip per call. */ reuseReceipts?: boolean; /** Header carrying the receipt. Default "X-DeroPay-Receipt" (the guard's default). */ receiptHeaderName?: string; /** ttlSeconds forwarded to the receipt issue endpoint. Unset: server default. */ receiptTtlSeconds?: number; }; /** * Returns a fetch-compatible function that transparently settles x402 * challenges under the given policy. Concurrent calls that hit the same * (origin, resource, amount) challenge share one payment instead of * double-paying, and a call that times out while settling leaves a * pending record the next call resumes — the payer never pays the same * demand twice. */ declare function createPayingFetch(config: PayingFetchConfig): (input: RequestInfo | URL, init?: RequestInit) => Promise; /** * x402 for MCP tools — the "paidTool" pattern (per-call payment gating, * free and paid tools mixed in one server), transport-agnostic so it * works over stdio and Streamable HTTP alike. * * No MCP SDK dependency and no separate facilitator: the guard mints * invoices through the merchant's own InvoiceEngine and verifies * DPAY-RECEIPT tokens locally. The payment travels as an `x402Payment` * tool ARGUMENT carrying either the paid invoice's id (fresh redemption) * or a previously issued receipt token (reuse), and the challenge comes * back as a `payment_required` tool result whose JSON matches the HTTP * 402 challenge body byte for byte — one parser serves both guards. * Replaying the paid call IS the settlement poll: while the invoice * confirms, the guard re-issues the SAME invoice's challenge with * `settling: true`, and the paying caller keeps waiting instead of * paying twice. */ /** Name of the reserved tool argument that carries the payment. */ declare const X402_PAYMENT_ARG = "x402Payment"; /** Marker embedded in payment_required tool results. */ declare const X402_MCP_ERROR = "payment_required"; /** Minimal MCP-shaped tool result the guard emits and inspects. */ type McpToolResult = { content: Array<{ type: string; text?: string; [key: string]: unknown; }>; isError?: boolean; _meta?: Record; [key: string]: unknown; }; type ToolHandler = (args: TArgs, extra?: unknown) => Promise | McpToolResult; /** Price of one guarded tool call. */ type PaidToolPricing = { amountAtomic: bigint; /** Invoice name. Default: `MCP tool: `. */ name?: string; description?: string; /** Invoice time-to-live. */ ttlSeconds?: number; requiredConfirmations?: number; }; type PaidToolGuardConfig = { getEngine: () => Promise; /** Secret used to sign and verify payment receipts. */ receiptSecret?: string; /** Secrets by key ID for receipt key rotation. */ receiptSecrets?: Record; /** Active key ID used to issue new receipts when receiptSecrets is set. */ receiptKeyId?: string; /** Fixed price, or a resolver called per tool invocation. */ pricing: PaidToolPricing | ((toolName: string, args: Record) => PaidToolPricing | Promise); /** Resource URI for a tool, bound into invoices and receipts. Default: `mcp:tool/`. */ resourceFor?: (toolName: string) => string; network?: DeroChainId; protocolId?: string; /** TTL for receipts minted on redemption. Unset: issueReceiptFromInvoice default (600s). */ receiptTtlSeconds?: number; /** * One paid call per payment (default true): each redeemed invoice and * each presented receipt is burned in the store's jti ledger, so a * payment cannot unlock a second call. Requires a store with * markReceiptJtiUsed (both built-in stores have it). Set false to let * a receipt be reused until it expires — it is then returned to the * caller in `_meta["deropay/x402"].receipt`. */ singleUse?: boolean; /** Called after each paid call is authorized, before the handler runs. */ onSettled?: (info: { toolName: string; resource: string; invoiceId: string; jti: string; }) => void; }; /** * Wrap tool handlers so each call requires a paid invoice. A call * without a payment argument gets a payment_required challenge naming a * fresh invoice; a call carrying a paid invoice id (or a live receipt) * runs the handler once the payment is verified against the engine. */ declare function createPaidToolGuard(config: PaidToolGuardConfig): { guard: >(toolName: string, handler: ToolHandler) => ToolHandler; resourceFor: (toolName: string) => string; }; /** Parse a tool result as a payment challenge, if it is one. */ declare function parsePaidToolChallenge(result: McpToolResult): X402Challenge | null; type CallTool = (toolName: string, args: Record) => Promise; type PayingToolCallerConfig = { callTool: CallTool; payer: InvoicePayer; policy: SpendGuard; /** * Policy origin under which MCP payments are accounted, e.g. the MCP * server's URL. Required because tool calls have no natural web origin. */ serverOrigin: string; /** Challenge protocol this caller honors. Default "x402-deropay-draft". */ protocol?: string; /** Refuse challenges on any other network. Unset: pay whatever the challenge names. */ network?: DeroChainId; onPayment?: (evidence: PaymentEvidence) => void; /** * How long to keep replaying the paid call while the invoice settles. * The SAME invoice id is replayed — never a second payment. Default 180s. */ settleTimeoutMs?: number; /** Delay between settlement replays. Default 2.5s. */ settlePollIntervalMs?: number; }; declare class X402ToolPaymentRejectedError extends Error { readonly result: McpToolResult; readonly txid: string; readonly invoiceId: string; constructor(message: string, result: McpToolResult, txid: string, invoiceId: string); } /** * Wrap an MCP callTool so payment_required results are paid under the * spending policy and the call replayed with the paid invoice id until * the guard reports it settled. */ declare function createPayingToolCaller(config: PayingToolCallerConfig): CallTool; export { type CallTool, type CredentialDenialCode, CredentialError, CredentialPolicy, type InvoicePayer, type InvoicePayment, type InvoiceStatusSnapshot, type McpToolResult, type PaidToolGuardConfig, type PaidToolPricing, type PayingFetchConfig, type PayingToolCallerConfig, type PaymentEvidence, type SpendCaveat, type SpendContext, type SpendCredential, type SpendDenialCode, type SpendGuard, SpendPolicy, type SpendPolicyConfig, SpendPolicyError, type SpendReservation, type ToolHandler, type WalletRpcPayerConfig, type X402Challenge, X402PaymentRejectedError, X402SettlementTimeoutError, X402ToolPaymentRejectedError, X402UnpayableError, X402_MCP_ERROR, X402_PAYMENT_ARG, attenuate, createPaidToolGuard, createPayingFetch, createPayingToolCaller, createWalletRpcPayer, createXswdPayer, isLoopbackUrl, mintSpendCredential, parseInvoiceStatusResponse, parsePaidToolChallenge, parseX402Challenge, verifyCredentialSignature };