import { z, ZodError } from 'zod/v4'; import { WalletClient } from 'viem'; interface SignZeroValueAuthorizationParams { walletClient: WalletClient; from: `0x${string}`; to: `0x${string}`; chainId: number; tokenAddress?: `0x${string}`; } interface ZeroValueAuthorization { signature: `0x${string}`; from: `0x${string}`; to: `0x${string}`; value: "0"; validAfter: string; validBefore: string; nonce: `0x${string}`; chainId: number; } /** * Signs a zero-value EIP-3009 `TransferWithAuthorization` for usage tracking. * The signed authorization proves the caller controls `from` without moving * any tokens — `value` is always 0. The aggregator verifies the EIP-712 * signature to attribute tool calls to unique callers. */ declare function signZeroValueAuthorization(params: SignZeroValueAuthorizationParams): Promise; declare const PricingEntrySchema: z.ZodObject<{ amount: z.ZodString; asset: z.ZodString; recipient: z.ZodString; protocol: z.ZodString; }, z.core.$strip>; declare const AccessRequirementSchema: z.ZodObject<{ kind: z.ZodString; data: z.ZodString; label: z.ZodString; links: z.ZodOptional>; }, z.core.$strip>; declare const AccessSchema: z.ZodObject<{ logic: z.ZodEnum<{ AND: "AND"; OR: "OR"; }>; requirements: z.ZodArray>; }, z.core.$strip>>; }, z.core.$strip>; declare const AttestationSchema: z.ZodObject<{ type: z.ZodString; endpoint: z.ZodOptional; enclaveHash: z.ZodOptional; maxAge: z.ZodOptional; transparencyLogURI: z.ZodOptional; }, z.core.$strip>; declare const ReproducibleBuildSchema: z.ZodObject<{ sourceCodeURI: z.ZodString; buildInstructions: z.ZodOptional; buildHash: z.ZodOptional; }, z.core.$strip>; declare const VerifiabilitySchema: z.ZodObject<{ tier: z.ZodEnum<{ "self-attested": "self-attested"; "hardware-attested": "hardware-attested"; verifiable: "verifiable"; }>; execution: z.ZodString; description: z.ZodOptional; dataRetention: z.ZodOptional>; sourceVisibility: z.ZodOptional>; attestation: z.ZodOptional; enclaveHash: z.ZodOptional; maxAge: z.ZodOptional; transparencyLogURI: z.ZodOptional; }, z.core.$strip>>; reproducibleBuild: z.ZodOptional; buildHash: z.ZodOptional; }, z.core.$strip>>; }, z.core.$strip>; declare const ToolManifestSchema: z.ZodObject<{ type: z.ZodOptional; name: z.ZodString; description: z.ZodString; version: z.ZodOptional; endpoint: z.ZodString; image: z.ZodOptional; featuredImage: z.ZodOptional; tags: z.ZodOptional>; inputs: z.ZodRecord; outputs: z.ZodRecord; creatorAddress: z.ZodString; pricing: z.ZodOptional>>; access: z.ZodOptional; requirements: z.ZodArray>; }, z.core.$strip>>; }, z.core.$strip>>; verifiability: z.ZodOptional; execution: z.ZodString; description: z.ZodOptional; dataRetention: z.ZodOptional>; sourceVisibility: z.ZodOptional>; attestation: z.ZodOptional; enclaveHash: z.ZodOptional; maxAge: z.ZodOptional; transparencyLogURI: z.ZodOptional; }, z.core.$strip>>; reproducibleBuild: z.ZodOptional; buildHash: z.ZodOptional; }, z.core.$strip>>; }, z.core.$strip>>; }, z.core.$loose>; type ToolManifest = z.infer; type PricingEntry = z.infer; type AccessRequirement = z.infer; type Access = z.infer; type Verifiability = z.infer; type Attestation = z.infer; type ReproducibleBuild = z.infer; type GateMiddleware = { check(request: Request, ctx: Partial): Promise; /** * Optional post-handler hook called after the user handler succeeds and the * output validates against the schema. Gates that move money (like x402) * settle here. The hook runs synchronously before the response is returned, * so a slow `settle()` adds latency to the response. A `settle()` that * throws is always logged; whether it also fails the response is decided by * `ToolHandlerConfig.settlement` (`"required"`, the default, withholds the * output; `"best-effort"` returns it anyway). */ settle?(ctx: ToolContext): Promise; }; interface InvocationEvent { callerAddress?: `0x${string}`; agentAddress?: `0x${string}`; /** * The caller's original verified EIP-3009 zero-value authorization, when an * auth gate (e.g. `predicateGate`) recovered one from the request. Carried * through so usage reporting can forward the caller's own signature instead * of re-signing server-side. */ callerAuthorization?: ZeroValueAuthorization; paid: boolean; payer?: string; settlementTxHash?: string; /** Chain ID where the x402 settlement tx was mined. */ settlementChainId?: number; /** * Set when a gate's `settle()` threw. Under `settlement: "required"` the * caller got a 502 with no output, but an ambiguous facilitator failure may * still have moved money, so the event fires anyway: it is the record an * operator needs to reconcile or refund. */ settlementFailed?: boolean; /** Resolved tool name from the manifest. */ toolName?: string; latencyMs: number; timestamp: number; } interface ToolContext { callerAddress?: `0x${string}`; /** When a delegated agent call is verified, this holds the agent's address. */ agentAddress?: `0x${string}`; /** * The caller's verified EIP-3009 zero-value authorization, stashed by an * auth gate so downstream usage reporting can forward the caller's own * signature rather than re-signing server-side. */ callerAuthorization?: ZeroValueAuthorization; gates: { predicate?: { granted: boolean; }; x402?: { paid: boolean; /** Payer address returned by the facilitator's /verify response. */ payer?: string; /** * Transaction hash of the onchain settlement, populated by the gate's * `settle()` after the facilitator confirms. */ settlementTxHash?: string; /** Chain ID where the settlement transaction was mined. */ settlementChainId?: number; }; }; manifest: ToolManifest; request: Request; } type EnvResolver = T | ((env: Record) => T); interface ManifestDefinition extends Omit { endpoint: EnvResolver; creatorAddress: EnvResolver; pricing?: EnvResolver; } declare function defineManifest(definition: ManifestDefinition): ManifestDefinition; declare function resolveManifest(definition: ManifestDefinition, env: Record): ToolManifest; type ValidateResult = { success: true; data: ToolManifest; } | { success: false; error: ZodError; }; declare function validateManifest(data: unknown): ValidateResult; /** * Returns top-level fields that are neither defined by the ERC-8257 schema nor * namespaced as extensions. These are committed by the manifest hash (the * manifest is hashed as served), but per ERC-8257 they SHOULD NOT occupy bare * top-level names, since that risks colliding with future normative fields. * Use this to warn authors to namespace their extension keys (reverse-DNS, or * the legacy `x-` prefix). * * Returns an empty array when `data` is not a JSON object. */ declare function findBareExtensionKeys(data: unknown): string[]; interface Eip3009UsageReporterConfig { /** * URL of the OpenSea usage endpoint. * Defaults to `https://api.opensea.io/api/v2/tools/usage`. */ aggregatorUrl?: string; /** * Chain ID used as the `chain_id` fallback for x402 settlement reports when * the gate did not record a settlement chain (e.g. 1 for Ethereum, 8453 for * Base). Forwarded EIP-3009 authorizations carry their own chain id. */ chainId: number; /** * ERC-8257 composite key: chain where the tool is registered. */ toolChainId: number; /** * ERC-8257 composite key: registry contract address. */ toolRegistryAddress: string; /** * Composite key: the tool's ID in the registry. A number (for onchain * tools that fit in a JS integer) or a numeric string (for x402 tools * whose IDs exceed `Number.MAX_SAFE_INTEGER`). */ toolOnchainId: number | string; /** * API key sent as `x-api-key` header. This authenticates the **tool * service** as the reporter. */ apiKey: string; /** * Request timeout in milliseconds. Defaults to 5000. */ timeoutMs?: number; } declare function createEip3009UsageReporter(config: Eip3009UsageReporterConfig): (event: InvocationEvent) => Promise; interface ToolHandlerConfig { manifest: ManifestDefinition; env?: Record; inputSchema: z.ZodType; outputSchema: z.ZodType; gates?: GateMiddleware[]; /** * What to do when a gate's `settle()` fails after the handler already ran. * * - `"required"` (default): withhold the output and return 502. The caller * was not charged, so returning the paid result would be giving the tool * away for free. Costs you the handler's work for that call, and a caller * who retries pays and gets the result. * With several settling gates, an earlier gate may already have settled * when a later one fails, so the caller can be charged by that gate and * still get a 502. Prefer a single settling gate. * - `"best-effort"`: log the failure and return the output with a 200 * anyway. Only safe when you replay failed settlements out-of-band and * can absorb the ones you never recover. Note that a settlement that * failed because the caller's authorization nonce was already spent can * never be replayed. */ settlement?: "required" | "best-effort"; handler: (input: TIn, ctx: ToolContext) => Promise; /** * Automatically reports tool usage to the OpenSea metrics endpoint. * * Fires as a fire-and-forget async call at the very end of the * handler lifecycle — after the response is built. Never blocks or * fails the tool call. Free invocations send a signed zero-value * EIP-3009 authorization; paid x402 invocations send the settlement * tx hash. */ usageReporting?: Eip3009UsageReporterConfig; /** * Called after the handler succeeds and output validates. Fires for * every successful invocation — paid or free. Use for custom * analytics or rate limiting. Errors are caught and logged. */ onInvocation?: (event: InvocationEvent) => void | Promise; /** * Platform "keep-alive after response" primitive (e.g. Vercel/Cloudflare * `waitUntil`). When available, the fire-and-forget usage report is * registered through it and the response is returned without awaiting the * report — so reporting never adds latency and a function freeze in the * report window can't leave a paid caller charged with no result. * * Usually you don't set this: it's auto-detected from the Vercel request * context, and `toCloudflareHandler` wires `ctx.waitUntil` for you. Pass it * explicitly only to override detection or to support another runtime. When * no `waitUntil` is available (long-running servers, or serverless without * it), the report is awaited instead so it still fires before the freeze. */ waitUntil?: (promise: Promise) => void; } declare function createToolHandler(config: ToolHandlerConfig): (request: Request) => Promise; export { type Attestation as A, type EnvResolver as E, type GateMiddleware as G, type InvocationEvent as I, type ManifestDefinition as M, type PricingEntry as P, type ReproducibleBuild as R, type SignZeroValueAuthorizationParams as S, type ToolManifest as T, type Verifiability as V, type ZeroValueAuthorization as Z, type Access as a, type AccessRequirement as b, AccessRequirementSchema as c, AccessSchema as d, AttestationSchema as e, type Eip3009UsageReporterConfig as f, PricingEntrySchema as g, ReproducibleBuildSchema as h, type ToolContext as i, type ToolHandlerConfig as j, ToolManifestSchema as k, VerifiabilitySchema as l, createEip3009UsageReporter as m, createToolHandler as n, defineManifest as o, findBareExtensionKeys as p, resolveManifest as r, signZeroValueAuthorization as s, validateManifest as v };