Conversation
* limit s array size * go/py * add changeset * fix fmt
* Update docs/extensions/builder-code.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/extensions/builder-code.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor --------- Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
* fix(python): preserve streaming bodies on payment retry Buffer request content before the initial send so a 402 retry replays the same body. * chore(python): use pull request number for changelog
* docs(svm): add `upto` SVM scheme specification SVM profile of the network-agnostic `upto` scheme: a single-authorization payment channel whose escrow deposit is the ceiling, settled at most once with an operator-signed voucher. Companion to scheme_upto.md and scheme_upto_evm.md. * docs(svm/upto): address review feedback on the upto spec Squashed response to the review on #2697: - Reframe the operator as "server/facilitator" and define it up front; a server can self-facilitate — nothing in the scheme requires a separate facilitator. - Drop the `permit` profile and all EVM/Permit2 framing; `payment-channel` is the single v1 profile and the spec is single-mechanism throughout. - Remove pay-kit attribution, the hardcoded program id, and "we control" — the channel program is identified via `extra.channelProgram`. - Require `channel.authorizedSigner == operator` at verify and clarify the anti-grief / escape-hatch properties; correct channel-rent ownership (funded by and refunded to the payer; the operator sponsors only the transaction fee). - Use USDC as the `asset` example; point multi-settlement to `batch-settlement`; remove the stray multi-delegator aside. * docs(svm/upto): align with payment-channels program semantics Addresses @notorious-d-e-v's program-grounded review: 1. Role model: the operator is the channel `payee` (the program requires the `settle_and_finalize` merchant == `channel.payee`), as well as the voucher `authorizedSigner`, fee payer, and `rentPayer`. The x402 `payTo` is realized as the payee (self-facilitating) or a program-enforced distribution split (separate facilitator) — so a third-party facilitator needs no program change. 2. Verifier pins `deposit == maxAmount` (was `≥`): `topUp` can raise an open channel's deposit, so equality is required to keep the ceiling enforced. 3. Time bounds are not client-bound: `expiresAt` is the operator's voucher value (on-chain enforced); `validAfter` is off-chain verify policy. The client signs only `open`. 4. `settle_and_finalize`/`finalize` only advance status; `distribute` is what moves funds (splits, payer refund, rent return) and closes the channel. 5. Zero-amount settlement uses the no-voucher path (`has_voucher = 0`) + `distribute`, since a `cumulative = 0` voucher is non-monotonic and invalid. * docs(svm/upto): note the v1 reference is self-facilitating (operator == payTo) The separate-facilitator model (payTo as a program-enforced distribution split) is specified but not yet implemented; the reference rejects an open whose payTo is not the operator. Matches the deposit==maxAmount + recipient guard added to the implementation (PR #2694). * docs: clarify upto svm channelProgram * docs: remove upto svm decimals field * docs: trim upto svm wire format text * docs: explain upto svm channel id derivation * docs: clarify upto svm settlement transaction * docs: align upto svm asset transfer method * docs: clarify upto svm open timing * docs: document upto svm rent cleanup * docs: document upto svm facilitator splits * docs(svm): align upto spec with payment channels * doc: channel discovery * docs(svm): facilitator as zero-share payee for upto scheme Set payee = extra.feePayer (zero-share) instead of receiverAuthorizer so the rent sponsor gains a unilateral cleanup path: settle_and_seal with has_voucher = 0, then distribute and reclaim. A client/server pair can no longer strand the facilitator's rent by leaving channels open. Nonzero settlement still requires the server voucher, and the distribution always sends 100% to payTo, so the facilitator holds lifecycle authority but no payment authority. Documents the residual trust: early close refunds the unsettled remainder to the client, so servers must settle promptly. * docs(svm): define upto open acceptance policy
…utside DEFAULT_STABLECOINS (#2924) * fix and tests * fix a slight permit2 regression * Create batch-settlement-explicit-asset.md
#2693) Let the resource server embed a recent blockhash in the `exact` 402 challenge so the client can build its payment transaction without its own RPC round-trip and against a blockhash the settling RPC has already observed. - utils: `resolveBlockhash(rpc, requirements)` — prefer `extra.recentBlockhash` (+ `extra.lastValidBlockHeight`) from the challenge, fall back to `getLatestBlockhash`. The `exact` client uses it instead of an unconditional RPC call. - exact/server: `ExactSvmScheme` takes an optional `{ rpcUrl }`. When set, `enhancePaymentRequirements` fetches a fresh blockhash and emits `extra.recentBlockhash` + `extra.lastValidBlockHeight` alongside `feePayer` (best-effort — omitted on RPC failure so the client falls back). Threaded through `registerExactSvmScheme({ rpcUrl })`. - spec: document the optional `extra.recentBlockhash` / `extra.lastValidBlockHeight` fields and the client's use of them in scheme_exact_svm.md.
* add tests * patch, tests green
* fix avm caip2 * update examples
* feat: add Solana support to cloudfront-lambda-edge example Each route now offers both Base Sepolia and Solana Devnet payment options via per-route accepts arrays; schemes are registered per namespace (eip155:*/solana:*) so concrete networks come from config. Updates the guides for dual-network setup, mainnet facilitators, and the real v2 402 response shape. * chore: update examples pnpm-lock for @x402 2.19 bump * docs: keep facilitator guidance neutral, name Solana wallet examples Revert the mainnet facilitator guidance to the neutral ecosystem-list phrasing the example shipped with (no facilitator is singled out) and name Phantom/Solflare as example Solana wallets alongside MetaMask.
…3126) * specs(exact): correct Starknet settlement and rescue rules (follow-up to #2849) Follow-up to #2849, aligning the merged spec with the reference implementation on the defects found by audit. Settlement's exactly-one-Transfer criterion is scoped to the payer, so an honest settlement is not denied when the asset is the STRK fee token (a real receipt then carries the executor's fee Transfer from the same contract). The consumed-nonce rescue was forgeable: a settled SNIP-9 payload is public, so a facilitator implementing step 5 as written would hand a fresh success to anyone replaying one off the chain. The rescue now requires an attempt this facilitator recorded (retained past the guard's horizon), re-established payload authenticity, an onchain nonce-consumption precheck, accepted-block finality, and a structural match identifying the authorization by callee, caller, and nonce - via a calldata parse or, more robustly, the execution trace, which works across the direct, forwarder, and Cairo-0 topologies. Crediting one transaction to at most one authorization per payer is a MUST, with the binding retained for as long as any rescue could locate the transaction, and the duplicate guard re-checked immediately before crediting. When the rescue credits nothing it reports its trigger's own outcome, never an unobserved nonce_already_used. Also: domain error codes are scoped to structured contract-level failures, with transport faults - including a simulation the node could not complete - failing closed as retryable unexpected_verify_error; settlement_pending carries an empty transaction when the broadcast itself timed out; the search window is sized against block time with legacy unkeyed scans spending their bounded budget newest-first; chainId always reduces to the felt; and the payment-flow vocabulary from #3053 is declared. Folds in block-tag pinning, chainId wire forms, an unsatisfiable-maxTimeoutSeconds rejection, and mandatory pre-hash size bounds. * specs(exact): align Starknet settlement_pending with the protocol-wide definition x402 v2 §9 (#3083) now defines settlement_pending for every scheme and requires the response to carry the broadcast transaction hash. The Starknet row and settlement step 4 reference that definition, and the hashless broadcast-timeout case - which has nothing to reconcile against - returns unexpected_settle_error while the duplicate guard and attempt record keep doing the protecting. * specs(exact): reconcile the Starknet overview block and settle on onchain The exact overview's Starknet block forbade an executor equal to the recipient while scheme_exact_starknet.md allows feePayer == payTo for merchant-sponsored settlement (the SVM precedent); the overview now says what the per-network document and the implementation do. The standard codes list names settlement_pending now that x402 v2 §9 defines it, and the document uses the repository spelling onchain throughout. * specs(exact): state the block-number gate in settlement step 3 Step 3 now says what the JSON-RPC paragraph and step 5 already relied on: a receipt counts only once it carries a block_number, for a REVERTED status as much as for SUCCEEDED. Step 5's nonce_already_used sentence names rule 6 as the source instead of over-stating it, and the overview block's last on-chain becomes onchain. * specs(exact): make a consumed Starknet nonce terminal and reconcile settlement_pending by hash Drops the consumed-nonce rescue from step 5, together with the authenticity, attempt-binding, structural-match and one-transaction-one-authorization rules that only existed to bound it. A settled SNIP-9 payload is public, so a success-on-consumed-nonce path lets anyone holding the payload obtain a second success: true for one onchain payment. settlement_pending stays the one non-terminal outcome: the resource server's retry with the same payload waits on the broadcast hash instead of broadcasting again. nonce_already_used and duplicate_settlement are terminal. Also states the asset transfer method's family instead of referring to SDK internals, restores the merged signature-bound SHOULD in place of implementation-specific input limits, and adds a note that Selector enters the hash as the felt, from a second implementer's interop report on #3021.
* spec(exact-hedera): add transferExecutor asset transfer method * spec(exact-hedera): address review feedback * spec(exact-hedera): tighten wording * spec(exact-hedera): trim the Hedera entry in Critical Validation Requirements * spec(exact-hedera): publish admitted executors in the quote Signed-off-by: Piotr Kierzniewski <piotr.kierzniewski@blockydevs.com> --------- Signed-off-by: Piotr Kierzniewski <piotr.kierzniewski@blockydevs.com>
* fix: protected endpoint price & ERC6492 allowlist * feat: updated tests * fix: revert default protected to avoid regression * fix: format
* fix(python): cap solana <0.40 in svm extra solana 0.40.0 removed the synchronous solana.rpc.api module that the SVM mechanism imports, so a fresh install of x402[svm] could not import x402.mechanisms.svm. Add an upper bound to the svm extra and the dev group; uv.lock only changes the two specifiers. Fixes #3552 * chore(python): add changelog fragment
* build(svm): generate payment channels client Co-authored-by: Ludo Galabru <ludo.galabru@solana.org> Signed-off-by: Ludo Galabru <ludo.galabru@solana.org> * refactor(svm): share payment channel lifecycle Co-authored-by: Ludo Galabru <ludo.galabru@solana.org> Signed-off-by: Ludo Galabru <ludo.galabru@solana.org> * feat(svm): add batch settlement scheme Co-authored-by: Ludo Galabru <ludo.galabru@solana.org> Signed-off-by: Ludo Galabru <ludo.galabru@solana.org> * fix(svm): preserve kit 5 codegen compatibility Co-authored-by: Ludo Galabru <ludo.galabru@solana.org> Signed-off-by: Ludo Galabru <ludo.galabru@solana.org> * feat(svm): align batch settlement with authorization flow Follow-ups from the spec review (#2698): - resolve batch-settlement to the protocol-default authorization payment flow; the deposit open/top_up now broadcasts in the single post-handler settle and its voucher commits after confirmation - stop emitting extra.paymentFlow; accept only absent or "authorization" on the wire - quantify the voucher-expiry margin: advertise a non-default extra.settlementBufferSeconds (default 60) and enforce expiry against the advertised value instead of private config Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(svm): require non-expiring batch vouchers Per spec follow-up: voucher expiry added a second clock on top of the forced-close grace period and could make an accepted voucher unredeemable while the channel was still open. Clients now always sign expiresAt = 0, the server and facilitator reject nonzero expiries with invalid_batch_settlement_svm_voucher_expiry, and the advertised extra.settlementBufferSeconds is removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(svm): confirm batch allocations and support topups * fix(svm): satisfy batch client lint * fix(svm): recover pending batch allocations * fix(svm): discard failed recovered batch opens * fix(svm/batch): record a top-up's escrow in stored channel state `ChannelState.deposit` was written once, when the channel is provisioned, and no store update ever changed it. A top-up's escrow therefore never reached stored state, so `snapshot()` kept reporting the original `open` amount as `channelState.balance`. Steady-state vouchers are answered by the server itself (`beforeSettle` short-circuits to `acceptedResponse`), so that stale balance is what the client receives — and the client adopts it as its own ceiling, overwriting the correct optimistic value it had just computed. The next request that exceeded the original deposit topped up again, and so did every request after it: the escrow grew on chain while the client believed it never had. It failed silently, as an ever-growing escrow rather than an error. The facilitator already reports the freshly-fetched on-chain deposit in `channelState.balance`, so the data was there and simply discarded. `readChannelState` now carries it and the deposit settle path adopts it, taking it as a maximum so a stale or malformed read can never lower a ceiling the chain has already confirmed. The regression test fails without the fix with `expected 10000n to be 25000n` — the stale open amount in place of the confirmed escrow. Found while porting this scheme to Rust, where the mirror of this bug (double-counting the same top-up on retry) was reported by Greptile on solana-foundation/pay-kit#301. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(svm/batch): report the real charged amount on a replay The settle response for a replayed authorization reported `chargedAmount: "0"`. A replay answers a request that was already charged the fixed price, so zero tells the client it paid nothing for a request it did pay for. Report `PaymentRequirements.amount`, which is what the original response carried and what §4.4 requires of the field. That was the only use of the `committed` flag, so it goes away with it. * added examples and few minor fixes * feat(svm/batch): recover unknown channels and emit the corrective 402 A voucher for a channel this server holds no record of was refused twice over — in `beforeVerify` and again in `provisionalState` — so a server that lost its store turned every request on a live, funded channel into a dead end, leaving the payer's escrow to a forced close. The facilitator already verifies a voucher against confirmed onchain state and returns the snapshot. Persist it: the record is rebuilt when missing and refreshed when present, so `deposit`, `settled` and the close state stop drifting behind the chain. A rebuilt record charges from the onchain settled watermark, which is both the most the server can honestly claim and the only base the program will accept — starting from zero would take vouchers `settle` can never apply, since it requires a strictly increasing watermark. The cumulative rule cannot run before the record exists, so for an unknown channel it moves after the snapshot lands and reports a mismatch the corrective 402 then carries. That 402 is new here: `voucherState` was typed as a whole `BatchVoucher`, was never emitted, and never consumed. It now has the spec's shape and travels with the snapshot, so the client can check the base against a signature only its own authorizer key could have produced — and when the server holds no voucher the proof is omitted and the client resynchronizes from chain. * test(svm/batch): cover channel recovery and the corrective 402 Nine cases across both sides: an empty store reaching the facilitator, the settled watermark as the rebuilt baseline, a closing channel refused, the corrective 402's snapshot and proof (and its absence when the server holds no voucher), and on the client, adoption only against its own signature — a foreign one, a base above the proof, and an unproven base are all refused. Also covers the trust boundary: a charge above the advertised price is refused, a cumulative the client cannot derive leaves local state alone, and the escrow comes from the deposit the client signed rather than the balance the server reports. Writing them turned up two fixes in the hook itself. It keyed the channel off the request context, which does not exist yet when the mismatch is caught before verification, so it now derives the channel from the payload — and only from one that validates, signature included, since otherwise naming a channel would be enough to read its state. `applySnapshot` also took two arguments it never read. * feat(svm/batch): reuse a wallet's channel and drive refunds The client salted every open with a random u64, so a restart opened a second channel and left the first one's escrow to a forced close. Salt now defaults to 0, and before funding anything the client looks for a channel this wallet already opened: a getProgramAccounts scan filtered on payer, narrowed to the terms in hand. Every scanned row has its PDA rederived from its own fields before it is trusted; a filter result never is. Discovery is an optimization over opening a new channel, never a precondition for paying, so a failed scan falls through to the open. The adopted base is the onchain settled watermark, which is where a server rebuilding its own record starts too, so the two agree. SVM could also build a payer-signed close but nothing drove it, where EVM ships refundChannel. refund(url) probes the route for the terms the channel was opened against, sends the close, and returns the settlement. It takes no amount — the program has no partial close — and has nothing to retry against a corrective 402, since a close carries no cumulative to resynchronize. It falls back to discovery too: a client with no local record is exactly the one that needs to close a channel it can no longer pay from. * fix(svm/batch): simulate redemption batches explicitly Claim and distribute went out through the rpc-based submitSettle, which left simulation to the node's preflight. A preflight rejection arrives as an opaque send error, and a batch packs several channels into one transaction, so a caller could not tell a poisoned batch from a flaky node — and would retry the same doomed batch forever. upto already had the shape this needs, in its own copy of submitSettle. Rather than add a third, the shared module now carries one signer-routed implementation and both submission paths build their transaction the same way. Batch's claim and distribute use it: simulate explicitly, report the failure as settlement_simulation, then let the signer broadcast with preflight skipped so the node does not simulate the same bytes twice. * test(svm/batch): drive the whole channel lifecycle onchain A local Surfnet forked from devnet serves the deployed payment-channels program and the devnet USDC mint, and its cheatcodes fund accounts, so the whole flow runs against a real chain with no pre-provisioned keys. Seven stages, sequenced as a channel's life: open and serve, a steady-state voucher with no transaction, a rediscovered client resynchronizing through a corrective 402 it verifies against its own signature, a server that lost its store rebuilding from chain, claim and distribute with the receiver's balance actually rising, a top-up when the escrow is spent, and the payer-forced close. Skips with an actionable message when no such RPC is reachable, so CI without a validator stays green. * fix(svm/batch): reconcile a broadcast instead of repeating it Every batch broadcast — deposit, refund, claim, distribute — went out behind an in-memory duplicate cache and confirmed inline. A confirmation wait that ends without an answer says nothing about the transaction: it may still land. The cache freed the lock on the way out, so a retry rebroadcast, and a restart lost the record entirely — the case the in-memory cache can never cover. The signature is now persisted through a PendingSettlementStore before the confirmation is awaited, so the next attempt reconciles against it rather than escrowing or redeeming a second time. A definite onchain failure drops the record and reports a failure; anything else stays pending, which is the conservative reading. The store defaults to memory as upto's does, and takes a durable implementation for deployments that need one. Top-up and refund also stop signing before they simulate: sigVerify is off, so the fee payer's signature adds nothing there, and not asking for it keeps simulation portable across signer backends that will not sign the same bytes twice. * feat(svm/batch): redeem stored channels on an interval Vouchers accumulate offchain and are worth nothing until claimed, so a server that never redeems forfeits everything it earned the moment a payer forces a close — the grace period is the whole window. The facilitator could claim and distribute on request, but nothing drove it. BatchChannelManager reads the server's own channel store, claims what has vouchers above its settled watermark, then distributes what those claims settled. Passes are serialized, so a slow one cannot overlap the next and submit the same claim twice, and a batch that does not land is left for the next pass rather than recorded — the onchain watermark is monotonic, so repeating a claim is harmless. Four channels per transaction, per the spec, with none dropped from a full batch. Enumerating needs a store that can list, which is optional on the interface so a store built only for serving requests need not implement it. The onchain suite drives redemption through the manager now: it claims, distributes, the receiver's balance rises, and a second pass finds nothing to do. Writing its unit tests turned up a bug — distribute filtered the snapshot the pass opened with, so a channel claimed in that same pass was never paid out. * fix(svm/batch): hold the pending record until the outcome is known The reconcile path dropped the pending record before confirming the signature it had just read. A concurrent retry that read the store after that delete found nothing and would broadcast the work a second time — and the in-memory duplicate cache that would otherwise catch it is empty after a restart, which is exactly when a pending record is being reconciled. Two callers reconciling the same signature is harmless: they confirm the same transaction and reach the same answer. The regression test asserts the record is still readable from inside the confirmation, which is where a racing retry would look; it fails on the old order. Reads now go through the facilitator signer too — channel accounts and the mint's owning token program — so an operator configuring one RPC does not find reads quietly answered by another. One read remains on its own client: simulateOpenSettleDistribute is shared with upto and simulates through an rpc it takes itself. * fix(svm): reconcile batch settlement with latest main * test(svm): cover batch settlement lifecycle * fix(svm): harden batch settlement lifecycle * fix(svm): address batch settlement review * feat(svm): add server-signed batch vouchers * fix(svm): recover batch transactions without new distribution request fields (#13) * fix(svm/batch): retry channel reads a lagging RPC rejects for the slot floor The remembered confirmation slot is passed as minContextSlot on every channel read, but only the postcondition pollers tolerated a rejection. A load-balanced RPC node behind that slot therefore failed ordinary deposit, claim and verify-time reads outright. Retry the floored read with the usual channel-read backoff before surfacing the error; reads without a floor still fail immediately. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(svm/batch): resolve expired broadcasts and ambiguous payouts instead of holding them pending Recovery follow-ups from the review of #13: - A broadcast whose confirmation was never observed is now checked against its own blockhash: when the signer reports it invalid and a history lookup still finds no record of the signature, the bytes can never land, so the operation is reported as transaction_failed and its queue released. The validity check precedes the history lookup so a transaction included just before expiry is still found. Anything uncertain stays pending. The facilitator signer gains an optional isBlockhashValid capability. - A confirmed sweep whose payout cannot be attributed because the merchant is also the refund or treasury beneficiary is answered with invalid_batch_settlement_svm_payout_attribution_ambiguous and the signature, and the sweep queue is released so later sweeps proceed. - Wire records written by a broadcast that lost its reservation are dropped. - Confirmation polling searches transaction history on the first lookup only. - Drop the unused PreparedDistribution fields and the ignored boolean on the claim and refund response builders; move the recovery helpers into recovery.ts to stay under the file-size limit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * test(svm/batch): cover refund, channel-manager and request-close edge paths Brings @x402/svm branch coverage back over the 90% gate (90.52%). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * ci: rerun flaky TypeScript tests * fix(examples): repair merged pnpm lockfile * ci: retry cancelled TypeScript tests * ci: limit TypeScript test concurrency * feat(svm/batch): advertise an idle window, wire the SVM e2e route, and close the review partials Review round of 2026-09-16 on #3164: - Idle abandon-close policy. Batch vouchers never expire, so an Open channel whose payer walks away used to lock sponsored rent forever, and any facilitator that cleaned it up privately would race the server on a clock the server could not see. The facilitator now advertises `extra.maxIdleSecs` (default seven days, `maxIdleSecs` config, `0` disables) and rent cleanup abandon-closes an Open channel at its onchain settled watermark once it has seen no facilitator-visible lifecycle activity for that long. Channel records carry `lastActivityAt`, reset by every deposit, claim and distribution the facilitator processes; servers copy the window into the 402 and the spec makes the forfeiture explicit (Phase 4, §4.1, §4.5, §6.2, §8). - SVM e2e harness. `/batch-settlement/svm` joins the SVM catalog for the TypeScript SDK; the TypeScript client, server and facilitator register the batch scheme, the client folds the harness salt to a u64 channel salt and drives the existing initial / recovery-refund / full phases, and the facilitator's EVM-only deposit read-back is now guarded by network. The phase env gains family-neutral names alongside the EVM_ aliases. - Dual RPC. The facilitator's open-deposit simulation runs through the signer's RPC like every other read; the redemption worker accepts an injected `rpc`. - Server `createChannelManager(facilitator, requirements, options)` builds the redemption worker over the scheme's store; the example server wires it for SVM the way it already does for EVM, and the example client refunds both channels in a dual-network run. - The facilitator's response builders move to `facilitator/responses.ts`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * style(examples): format the batch-settlement client and server wiring Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(svm): tighten server-signed batch vouchers * feat(svm/batch): make server-signed channels an explicit client trust decision (#23) * Receiver auth binding (#25) --------- Signed-off-by: Ludo Galabru <ludo.galabru@solana.org> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Philippe d'Argent <pdargent@icloud.com> Co-authored-by: Notorious D.E.V. <notoriousd3v@gmail.com>
* Update docs/sdk-features.md Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/core-concepts/network-and-token-support.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor --------- Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
The lnbtc spec is on main. The scheme pages still omitted it.
…3594) * fix(e2e): build the TypeScript SDK before family selection ci-select-families loads mechanisms.ts, which imports @x402/cardano. That package exports dist/cjs/index.js, and dist/ is gitignored, so a fresh checkout cannot resolve it until the SDK is built. The workflow treated that crash as missing wallet secrets and skipped the suite. Build the SDK first, and skip only when family selection exits 2. Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com> * fix(e2e): load @x402/cardano only when resolving server routes Family selection imports the mechanisms catalog before the SDK is built. That catalog value-imported @x402/cardano, whose exports point at gitignored dist/. Pass masumiEscrowAddress in from the TypeScript server catalog, which starts after the build. Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com> * fix(e2e): drop the catalog note on the cardano helper Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com> --------- Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com>
* fix(e2e): retry Solana devnet 429s in swig setup Public devnet returns HTTP 429 during Swig funding when SVM_TESTNET_RPC_URL is unset. swig-setup treated that as fatal, so the e2e job died after the account was created. Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com> * fix(e2e): inline public-devnet 429 retry in swig-setup Keep the HTTP 429 backoff in the setup script and drop the helper module and tests. Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com> --------- Co-authored-by: phdargen <29732335+phdargen@users.noreply.github.com>
Enable dollar-string pricing on Arc mainnet (chain ID 5042) and Arc Testnet (chain ID 5042002) across the TypeScript, Go and Python SDKs, plus the paywall faucet link for the testnet. Arc is Circle's own L1 and uses USDC as its gas token, so USDC at the predeploy address 0x3600000000000000000000000000000000000000 is the chain-endorsed stablecoin. The same address serves both networks. EIP-712 domain values were read from the token contracts and the resulting domain separators match DOMAIN_SEPARATOR() on both chains. The token exposes EIP-3009, so no transfer-method override is needed. Decimals stay 6, so the generated paywall decimals map is unchanged.
* docs(go): fix relative links in the Go client guide Co-authored-by: Claude <noreply@anthropic.com> * docs(go): fix relative links in the Go server guide * docs(go): fix relative links in the Go facilitator guide * docs(examples): fix builder-code facilitator link (TypeScript) * docs(examples): fix builder-code facilitator link (Python) * docs(examples): fix fetch client link in the CloudFront CDK guide * docs(examples): fix fetch client link in the CloudFront console guide * docs(examples): fix auth-capture spec links * docs(extensions): fix package README link in bazaar * docs(extensions): fix package README links in builder-code * docs(extensions): fix package README link in payment-identifier * docs(extensions): fix package README link in sign-in-with-x * docs(python): fix examples link in the MCP README * docs(agents): fix CONTRIBUTING link in the contributing skill * docs(specs): point the transport template to the v2 specification * docs(specs): link the v1 A2A transport to the v1 specification * docs(specs): link the v1 MCP transport to the v1 specification --------- Co-authored-by: Claude <noreply@anthropic.com>
The batch-settlement server and facilitator derive the channel PDA from the payload's channel config on every request. At ~240 us per call it was the largest single cost on the server's per-request path, most of it the SHA-256 + off-curve bump search. Memoize the derivation in a bounded LRU (4,096 entries) keyed on the exact bytes it hashes: the program address and every encoded seed. Inputs are still read, validated and encoded as before on every call, so results and errors are unchanged for any input; a hit skips only the hash. A program address that is not a primitive string is hashed as given, so it is derived uncached.
* feat(evm): add Monad testnet USDC default asset Register eip155:10143 USDC in the TypeScript, Go, and Python default asset tables and map v1 network monad-testnet so "$0.10" pricing resolves on Monad testnet. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(evm): use Circle USDC on Monad testnet The Monad testnet default asset should match Circle faucet USDC at 0x534b2f3A21130d7a60830c2Df862319e593943A3, not the chain-native test token. Add Circle faucet URL for eip155:10143 in the paywall. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
* docs(express): add Solana Mainnet setup * docs: pair Solana and EVM across middleware README examples
…ymentchannels refactor (#3603) * feat(svm): refactor signer * refactor(svm): batch signer assert and confirmation-slot proxy Revert FacilitatorSvmSigner type split; keep batch construction-time capability checks and replace submissionSigner() with a confirmTransaction proxy for minContextSlot reads. Co-authored-by: Cursor <cursoragent@cursor.com> * refactor svm upto -> paymentchannels * use generated types directly * feat(go): Implement svm batch-settlement * patches * patch e2e * channel pda cache * add changesets * fix fmt * cleanup * ts: unify storage * go: unify storage * update spec * add atomic storage comment * patch recordOpen race --------- Co-authored-by: Cursor <cursoragent@cursor.com>
* Update docs/sdk-features.md Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/schemes/batch-settlement.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor * Update docs/core-concepts/network-and-token-support.mdx Generated-By: mintlify-agent Mintlify-Source: dashboard-editor --------- Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com>
* feat(paywall): add rpcUrls config for the SVM paywall The SVM paywall reads the payer's USDC balance and builds the payment transaction from the browser against api.mainnet-beta.solana.com, which returns 403 to browser-origin requests. Mainnet payments through the built-in paywall fail at the balance check. Add a CAIP-2 keyed rpcUrls map to PaywallConfig, mirroring faucetUrls, and use the entry for the payment network in the balance hook and the ExactSvmScheme client. Networks without an entry keep the public default. * chore(paywall): regenerate SVM paywall templates * feat(go,python): pass paywall rpcUrls through to the SVM template The Go and Python servers render the same SVM paywall template as @x402/paywall, so without this they could not configure the browser RPC and stayed on the public mainnet endpoint that rejects browser requests. Add RPCURLs (Go) and rpc_urls (Python) to PaywallConfig, keyed by CAIP-2 like FaucetURLs / faucet_urls, and inject them as window.x402.rpcUrls in every path that renders the template. * fix(python): honor faucet_urls in the built-in paywall template path x402HTTPServerBase._inject_paywall_config, used when no paywall provider is registered, never passed faucet_urls, so the setting was silently ignored there. The Go server injects it on the equivalent path. * ci: run the paywall template check on paywall pull requests The check has been workflow_dispatch only since #2313, and nothing else regenerates the templates: publishing runs tsup, not build:paywall. The committed templates went stale, and paywall source changes merged since then (#2931, #3025, #3124, #3227) never reached the shipped bundles. Run it again on pull requests, limited to paywall source and the generated files so PRs that only change core, mechanisms, the lockfile, tests or versions stay unaffected. Document the full regen steps CI uses, including build:paywall-deps. * chore(paywall): regenerate EVM and AVM paywall templates Last regenerated in #2160. Picks up paywall source changes merged since (#2931 Algorand CAIP-2 refs, #3124 spend controls, #3025 and #3227 faucet links) plus the core and mechanism changes the bundle includes. Generated with the CI steps: install --ignore-scripts, build:paywall-deps, build:paywall. * fix(paywall): use each Solana network's own rpcUrl in the payment client The paywall registered one ExactSvmScheme for solana:* with the RPC of accepts[0].network, but x402Client pays the first requirement it supports, which can be on another Solana network. Register a scheme per configured network instead; exact matches win over the wildcard. * docs: point DEFAULT_ASSETS paywall steps at the CI regen recipe * chore(python): name the changelog fragments after the PR * fix(paywall): escape rpcUrls for the inline script JSON.stringify leaves "<" as is, so an rpcUrls value containing "</script>" would end the paywall's inline script element. Serialize it with toScriptJson, which escapes "<" as <. The helper is the same one #3600 introduces for the other window.x402 values. * chore(paywall): regenerate templates after merging upstream main CI regenerates on the merge ref; upstream #3590 (Arc default stablecoins) changed faucetUrls after this branch was cut, so the nine committed snapshots were one line stale against main.
* test(svm): cover server-signed refund recovery after restart A restarted client with discovery disabled must refund the persisted server-signed channel when the operator is trusted, and must refuse before reading that record when the operator is not. Co-authored-by: phdargen <phdargen@users.noreply.github.com> * fix(svm): restore server-signed channel refunds after restart Refund lookup rewrote server-signed requirements to client mode before reading durable storage. With discovery disabled, that skipped the persisted server-signed record and returned ErrNoBatchChannelToRefund. The server-mode fallback now calls loadRefundChannel after serverSignedChannelsPolicy accepts the operator. The client-signed fallback is unchanged. Co-authored-by: phdargen <phdargen@users.noreply.github.com> --------- Co-authored-by: phdargen <phdargen@users.noreply.github.com>
* fix: fastify path bypass * fix: pr review feedback
#3655) * fix: derive batch-settlement charge baseline from onchain totalClaimed * fix: pr review feedback
#3661) * fix(svm): enforce settled + amount minimum at batch facilitator verify * align with evm 0-voucher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Tests
Checklist