## What's changed **Breaking.** A paid tool whose settlement fails now returns 502 without the output, instead of 200 with the result. `createToolHandler` gains `settlement`, defaulting to `"required"`. Set `settlement: "best-effort"` to restore the previous behavior, which only suits callers who reconcile failed settlements out of band. This is a minor version because the package is pre-1.0, not because the change is small. Also in this release: - `replayGuard` on the hosted x402 gates and `paidPredicateGate`, an optional single-use claim over each authorization's `(payer, nonce)` pair. Off b
## What's Changed - Reject negative and malformed x402 payment amounts. A negative `maxAmountRequired` previously slipped under the signed-BigInt `maxAmount` cap check and, when signed, wrapped into a huge positive `uint256` EIP-3009 authorization, bypassing the caller's spending limit. Amounts are now validated as canonical non-negative integers in `validatePaymentRequirements` (unconditionally, even without a cap) and again in the EIP-3009 signer as defense-in-depth for direct `signX402Payment` callers. (#530) - Updated dependency `@opensea/wallet-adapters` to 0.3.3 (EIP-712 encoding hardeni
## What's Changed - **fix(tool-sdk): scope predicate gate reads to the configured chain** (#520): `predicateGate`/`paidPredicateGate` no longer force reads to the Base RPC when `rpcUrl` is unset, so a non-Base registry chain is actually queried. The x402 identity/payment chain (Base/Base-Sepolia) is decoupled from the registry chain so non-Base gating no longer fails closed. Includes regression tests for a non-Base registry with Base identity/payment. **Full Changelog**: https://github.com/ProjectOpenSea/opensea-devtools/compare/tool-sdk-v0.28.2...tool-sdk-v0.28.3
## What's Changed Security and hardening patch release. ### Security - **`paidAuthenticatedFetch` per-invocation `maxAmount` cap** (#508): at most one nonzero x402 authorization is signed per call, and cumulative authorized value can never exceed `maxAmount`. Closes a double-challenge bypass where a malicious tool could obtain two independently-settleable authorizations, each under the cap. - **`verifyXPaymentAuth` hardening** (#509): the free `predicateGate` rejects non-zero-value X-Payment authorizations, `validBefore` is capped to 1h, the resolved chainId is pinned to the gate's chain, and
## What's Changed ### Security - `eip3009AuthenticatedFetch` now validates the 402 challenge's `asset` and `network` before signing: the network must be supported and the asset must be the canonical USDC contract for that network. This closes a signature-phishing surface where a zero-value challenge could name an arbitrary verifying contract / EIP-712 domain and still get signed (#507). - `eip3009AuthenticatedFetch` enforces the documented zero-value guarantee: it only signs `X-Payment` authorizations with `value: 0`, and returns non-zero (or unparseable-amount) 402 challenges as-is instead of
## What's Changed - Add **Robinhood Chain (4663)** support: `--network robinhood` on all CLI commands (custom viem chain definition until viem ships one) and 4663 added to every canonical `Deployment.chains` array in `chains.ts`. - Fix x402 CAIP-2 network handling asymmetry: server-side predicate gates now accept CAIP-2 (`eip155:8453`) and numeric (`8453`) network identifiers in the `X-Payment` payload, and the client normalizes the v1 payload `network` to the canonical short name. - Fix x402 usage reporting when the facilitator returns a CAIP-2/numeric network: `settle()` resolves the settlem
## What's Changed - feat: add Monad (chain 143) support. The `--network` flag now accepts `monad` in addition to `base`, `mainnet`, `shape`, and `abstract`. Monad is defined locally (mirroring viem's definition) because the pinned viem version predates Monad mainnet. `143` is added to every `Deployment.chains` array in `chains.ts`, and the deployed-address docs are updated: the canonical v0.2 addresses are identical on Monad (verified via CREATE2 dry-run). (#477) **Full Changelog**: https://github.com/ProjectOpenSea/opensea-devtools/compare/tool-sdk-v0.26.1...tool-sdk-v0.27.0
## What's Changed - Fix `createBankrAccount` reading the wrong shape from Bankr's `/wallet/me`. The endpoint returns `{ wallets: [{ chain, address }, ...] }` (no top-level `address`), so the account was created with an undefined address. Now resolves the EVM entry from `wallets[]`. (#473) - Picks up the `@opensea/wallet-adapters@0.3.2` dependency bump (BigInt EIP-712 signing fix). **Full Changelog**: https://github.com/ProjectOpenSea/opensea-devtools/compare/tool-sdk-v0.26.0...tool-sdk-v0.26.1
## What's Changed ### Minor Changes - **BREAKING**: Unify `predicateGate` to use the standard 402 + X-Payment (EIP-3009) auth flow only (#471). - `PredicateGateConfig.operatorAddress` is now **required** (was optional) - `Authorization: EIP-3009 <token>` header is no longer accepted: use the X-Payment header via the 402 challenge flow - `Authorization: SIWE <msg>.<sig>` header is no longer accepted (was already deprecated) - CLI `dry-run-predicate-gate` now requires `--operator-address` and asserts a 402 response ### Fixes - Use the Bankr `/wallet/me` endpoint instead of `/wallet/info` (#470).
## What's Changed - **feat:** The `register` command now validates that the manifest URL and declared endpoint share the same origin before sending the onchain transaction. Previously only `verify` and `deploy` checked this, so a developer could burn gas registering a tool the indexer would immediately reject. All three commands (`register`, `verify`, `deploy`) now show a consistent, actionable error message that explicitly calls out subdomains as different origins and explains how to fix it. (#465) **Full Changelog**: https://github.com/ProjectOpenSea/opensea-devtools/compare/tool-sdk-v0.24.0
## What's Changed - Add support for the `upto` x402 payment scheme, which allows variable pricing (charge up to `amountPerCall`, with the actual charge potentially less). `createX402Client` now registers both `ExactEip3009Scheme` and `UptoEip3009Scheme` internally, letting `@x402/core` route to the correct scheme based on the challenge's `scheme` field. The `pay` CLI, `paidFetch`, and `paidAuthenticatedFetch` route to the appropriate scheme automatically, so callers no longer need to know which scheme to instantiate. (#459) **Full Changelog**: https://github.com/ProjectOpenSea/opensea-devtools
## What's Changed - `--tool-ref` and the usage reporters now support non-address registries such as `x402:bazaar` and `x402:bankr` for tools that are not registered onchain (#455). `toolRegistryAddress` is widened to `string`, and `toolOnchainId` is kept as a string to preserve precision for IDs exceeding `Number.MAX_SAFE_INTEGER`. - `--tool-ref` now uses a **comma** delimiter (`chainId,registryAddress,onchainId`) instead of a colon, so a registry identifier that itself contains a colon stays unambiguous (#457). Example: `8453,x402:bazaar,8679018179619845322`. **Full Changelog**: https://githu
## What's Changed - Caller-side usage reporting can now identify a tool by its ERC-8257 composite key instead of only its endpoint URL. `reportCallerX402Usage` accepts optional `toolChainId`, `toolRegistryAddress`, and `toolOnchainId`, and the `pay` CLI gains a `--tool-ref <chainId:registryAddress:onchainId>` flag (e.g. `--tool-ref 8453:0x265b...2cf1:65`). When supplied, these are sent in place of `tool_endpoint`, matching the server-side reporter's payload. This fixes the `400 Multiple tools registered for endpoint` error when reporting usage for a tool whose endpoint maps to more than one re
## What's Changed - Migrate `paidFetch`, `paidAuthenticatedFetch`, and the `pay` CLI to the `@x402/core` client infrastructure (`x402Client`, `x402HTTPClient`, `SchemeNetworkClient`) for payment payload creation and header encoding. Adds an `ExactEip3009Scheme` adapter wrapping tool-sdk's existing EIP-3009 signing into the standard x402 scheme interface. No public API changes. (#447) This also resolves a payment-blocking bug in the previous home-rolled encoder: `btoa(JSON.stringify(...))` threw `InvalidCharacterError` whenever a server's 402 challenge echoed a non-Latin1 character (e.g. an em-
## What's Changed - **Usage report fires via platform `waitUntil`** (`createToolHandler`): the fire-and-forget usage report now runs as keep-alive-after-response work instead of being awaited inline. This removes reporting latency from every successful call and closes a billing edge — x402 settlement runs before the report, so awaiting it meant a function freeze in that window could charge a paid caller without returning a result. Auto-detected on Vercel (no `@vercel/functions` dependency), wired on Cloudflare via `toCloudflareHandler` (its `fetch` gains an optional `ctx` arg), overridable via
## What's Changed - **Caller usage reporting, default-on:** `pay` now sends a caller-side usage report by default (`--no-report-usage` to opt out). `--api-key` falls back to `OPENSEA_API_KEY` before auto-provisioning an instant key. A duplicate-report rejection (the tool's own server-side reporter already recorded the settlement) is treated as success. `reportCallerX402Usage` / `reportCallerEip3009Usage` now return a `CallerUsageReportResult` (`reported` | `already-reported` | `skipped` | `failed`) so callers can surface the real outcome. (#445) - **Reject x402 payment on 5xx:** `paidFetch` an
## What's Changed - **Caller-side usage reporting**: new `reportCallerX402Usage`, `reportCallerEip3009Usage`, and `extractSettlementTxHash` exports. Tool callers can report usage by endpoint URL with auto-provisioned API keys, integrated into `paidFetch`, `paidAuthenticatedFetch` (via the `reportCallerUsage` option), and the `pay` CLI (`--report-usage`). - **Settlement-response header from `createToolHandler`**: after a paid call settles, the handler now echoes the onchain settlement tx hash to the caller via `PAYMENT-RESPONSE` (v2) / `X-PAYMENT-RESPONSE` (v1). This lets caller-side reporting
## What's Changed Support x402 v2 and GET endpoints in `pay` (#437). Bazaar-discovered x402 tools are frequently GET endpoints that speak x402 v2, where the SDK previously could not transact at all: `pay` only issued POST, only read the v1 body `accepts` challenge, and signed the v1 `X-PAYMENT` envelope. - New `x402-challenge.ts`: `resolveNetwork()` accepts `base`, `eip155:8453`, and `8453`; `parseX402Challenge()` reads the `PAYMENT-REQUIRED` header or the body and normalizes the v2 `amount` field to `maxAmountRequired`. - `signX402Payment` emits the version-correct envelope (v1 `{scheme,netwo
## What's Changed - Hash the manifest as served, per ERC-8257 §2: the full JCS document including any namespaced extension fields, with no schema stripping and no injected defaults. The result agrees with any RFC 8785 implementation and with the OpenSea backend. - `computeManifestHash` now accepts the raw served or authored object and hashes it as-is. - The manifest schema is open: namespaced extension fields (reverse-DNS, e.g. `io.opensea.paymentHint`, or the legacy `x-` prefix) are preserved. The `type` field is no longer defaulted. - `validate`, `hash`, and `register` warn about bare un-nam
## What's Changed - Thread `--rpc-url` through to registry reads in CLI commands. Previously the flag only applied to writes; read paths (status, get, list) fell back to the default RPC endpoint. (#426) - Add ERC-8257 image metadata to chonks and overlap example tool manifests. (#423) **Full Changelog**: https://github.com/ProjectOpenSea/opensea-devtools/compare/tool-sdk-v0.17.0...tool-sdk-v0.17.1
## What's Changed ### Minor Changes - Sync the manifest schema with the canonical ERC-8257 spec: `featuredImage` is now an optional field in the manifest Zod schema, so manifests declaring it pass validation. (#419) ### Patch Changes - Remove the broken `--auth eip3009` path from the `pay` CLI command (along with its `--manifest` and `--chain` options). The flag bypassed the unified x402 flow (probe → 402 → sign X-Payment → retry) and caused 500 errors. `pay` now always uses the probe-then-sign path. (#421) - Update example READMEs to remove `--auth eip3009` usage. (#422) **Full Changelog**: h
## What's Changed - **Security fix:** `validBefore` is now required in predicate-gate authorizations. Previously a caller could sign a `TransferWithAuthorization` with `validBefore=0` and omit the field from the X-Payment payload, so the expiry check was skipped and the gate accepted an unbounded, non-expiring proof. The field is now required in both the X-Payment and EIP-3009 auth paths, with the now-dead `validBefore !== undefined` guards and the `?? "0"` recovery fallback removed. ## Community Contributions - Reported and fixed by @Nexory (ProjectOpenSea/tool-sdk#9, ProjectOpenSea/tool-sdk#
## What's Changed - **feat: `paidPredicateGate`** (#409): a combined gate that resolves identity verification (predicate) and x402 payment in a single 402 round trip. Tools using it need only 2 requests (a 402 advertising the real payment amount, then a 200) instead of 3. The caller's `X-Payment` signature proves identity, via the recovered `from` address, and authorizes the transfer in one step. The onchain predicate is checked before the facilitator settles payment, so denied access returns a 403 and moves no funds. New exports: `paidPredicateGate` and `PaidPredicateGateConfig`. - docs: pred