Repository navigation
Conversation
lgalabru
force-pushed
the
feat/svm-transaction-versions-exact
branch
from
September 14, 2026 18:20
929a210 to
76ebd65
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
from
September 14, 2026 18:20
950872d to
ff46809
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-exact
branch
from
September 14, 2026 18:24
76ebd65 to
614d650
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
from
September 14, 2026 18:24
ff46809 to
f8f864e
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-exact
branch
from
September 14, 2026 18:25
614d650 to
7a5dc4f
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
2 times, most recently
from
September 15, 2026 03:18
a135c3f to
f53b855
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-exact
branch
from
October 6, 2026 15:35
fa2cdb4 to
68edcb3
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
from
October 6, 2026 15:35
7f88c04 to
73c6fdd
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-exact
branch
from
October 6, 2026 15:53
68edcb3 to
631f006
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
2 times, most recently
from
October 6, 2026 15:55
de98fa4 to
315f556
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-exact
branch
from
October 26, 2026 19:20
631f006 to
c7b2814
Compare
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
3 times, most recently
from
October 26, 2026 19:53
0b77470 to
50addd4
Compare
…ndation#3221) * docs(exact/svm): add multi-payee splits to the exact scheme Adds an optional `extra.splits` array to the SVM `exact` scheme so a single client payment can be distributed atomically across the merchant (`payTo`) and up to eight additional recipients — for platform fees, revenue sharing, referral commissions, and fee-payer cost recovery. Design: - Absolute amounts in base units (not basis points); the primary `payTo` receives the remainder `amount - sum(splits[].amount)`, which MUST be > 0. - Each payment leg matches a distinct on-chain `TransferChecked`; split legs match exactly, the primary leg keeps the base overpayment tolerance. - Fee-payer-funded ATA creation is a bounded, opt-in exception to fee-payer isolation: allowed only for split recipients marked `ataCreationRequired`, forbidden for the primary recipient and arbitrary owners. - Backward compatible: absent/empty `splits` behaves as single-payee `exact`. Adds a self-contained §5 to scheme_exact_svm.md with surgical pointers from §1–§3, and a network-agnostic "Multi-Payee Splits" note to scheme_exact.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Update specs/schemes/exact/scheme_exact_svm.md Co-authored-by: phdargen <pdargent@icloud.com> * docs(exact/svm): address review feedback on multi-payee splits - Advertise split support in /supported (maxSplits, ataCreationSponsored) instead of leaving it as unadvertised local policy; absent means none. - Allow fee-payer-funded ATA creation for the primary payTo as well as split recipients, gated by explicit opt-in on both sides (extra.ataCreationRequired / ataCreationSponsored) and client consent. - Require CreateIdempotent over Create and let the client omit the instruction when the ATA already exists. - Drop the informational per-split memo. - Simplify the client-side ataCreationRequired rejection rule. * docs(exact/svm): restore per-split memo as the client consent label Keeps wire parity with splits[].memo in the MPP Solana charge draft and gives wallets a label to show the payer for each leg. Still never emitted on-chain and not verified by the sponsor. * docs(exact/svm): generalize Path 1 cap and Path 2 isolation for splits - §3.1/§5.7: replace the fixed 3–7 cap with 3+N+K to 7+N+K for split / ATA-creation charges, with positional leg matching, so standard wallets stay on Path 1. - §3.2: Path 2 fee-payer isolation references the bounded CreateIdempotent exception. - §2.2.2: exempt the ATA program for §5.4-conforming CreateIdempotent. - §5.5: explain why maxSplits / ataCreationSponsored live in kinds[].extra (fail-closed) rather than a x402-foundation#2498 capabilities map. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(exact/svm): make base rules split-aware and tighten ATA sponsorship - §1.1 / parent: scope single-transfer outcome to single-payee; per-leg remainder rule with splits, parent amount/destination bullets. - §3.4 / I4: post-settlement matches N+1 legs, per-leg balance deltas. - splits[].amount: positive integer in u64 range; parent states the primary >= / split == asymmetry. - §2.1.1: enumerate fee-payer positions in CreateIdempotent (funding payer, wallet owner) and the rent CPI; drop the once-per-mint bound (owner can close the ATA) and require sponsor policy for repeats. - ataCreationRequired always means fee-payer-funded; drop client-funded creation, which contradicted the advertisement rule. - Hints list covers only recentBlockhash / lastValidBlockHeight. - splits[].memo is bound payment terms, shown with the address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(exact/svm): align memo consent in parent and I11, retitle I9 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(exact/svm): extend split layout and size limits to v1 transactions Main now specifies v1 transactions (no Compute Budget instructions, 4096-byte limit, no ALTs). Scope the v1 1-5 layout to single-payee, add the 1+N+K..5+N+K split window, use per-version size limits in §5.2, and require loadedAccountsDataSizeLimit to cover the ATA program. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: phdargen <pdargent@icloud.com>
* feat(go): advertise and enforce SVM transaction versions in exact Exact facilitators (current and legacy x402 v1 wire) publish extra.transactionVersions ([0]) in /supported, servers copy it into PaymentRequirements.extra, and clients fail fast with unsupported_transaction_version when version 0 is not advertised. Verifiers reject any message version other than legacy or 0 before inspecting signatures or instructions; legacy stays accepted for backward compatibility but is deprecated and never advertised. The shared helpers in svm/utils.go are reused by the upto scheme in a follow-up. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(ts): advertise and enforce SVM transaction versions in exact Exact facilitators (current and legacy x402 v1 wire) publish extra.transactionVersions ([0]) in /supported, servers copy it into PaymentRequirements.extra, and clients fail fast with unsupported_transaction_version when version 0 is not advertised. The exact static and smart-wallet verifiers reject any message version other than legacy or 0 before inspecting signatures or instructions; legacy stays accepted for backward compatibility but is deprecated and never advertised. The shared constants and helpers are reused by upto in a follow-up. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(py): advertise and enforce SVM transaction versions Facilitators publish extra.transactionVersions ([0]) in /supported, the server copies it into PaymentRequirements.extra, and clients fail fast with unsupported_transaction_version when version 0 is not advertised. Verifiers reject any message version they do not model before inspecting instructions; legacy messages stay accepted for backward compatibility but are deprecated and never advertised. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(svm): fail closed on transaction version metadata * fix(svm): negotiate highest mutual transaction version * fix(svm): fail closed on any non-integer transactionVersions entry The merged spec (x402-foundation#3473) limits extra.transactionVersions to the integers 0 and 1 and requires a field with any other entry (string, null, "legacy", unknown integer) to fail closed instead of being skipped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(svm): reject real v1 wire bytes before decoding; build the negotiated version - TS and Python verifiers read the message version from the raw wire bytes before the SDK decoder runs, so a SIMD-0385 v1 payload is reported as unsupported_transaction_version instead of a decode error, whatever the installed kit or solders does with it. - Tests feed real 0x81 payloads (Go-style retag and the SIMD-0385 layout) through verify and settle and assert nothing is signed or simulated. - The Python clients compile the version resolve_transaction_version returns instead of discarding it. - Go maps wire versions to solana-go MessageVersion explicitly instead of selected+1, which only holds for version 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(specs): name the SVM v1 config mask bits and scope the Compute Budget rule SIMD-0385 carries the v1 budget in TransactionConfigMask bits, not in a TransactionConfig struct: bits 0-1 priority fee (u64 lamports), bit 2 compute-unit limit, bit 3 loaded-accounts data size limit, bit 4 heap size. Name the bits, state that unset values request the minimum (the cost model still reserves 32 KiB for a 0 data-size limit, but the budget is 0), and say that rejecting Compute Budget instructions in v1 is an x402 sponsor rule, since the runtime treats them as no-ops. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The upto facilitator publishes extra.transactionVersions ([0]) in /supported, the client fails fast with unsupported_transaction_version when version 0 is not advertised, and the payment-channels open verifier and the upto settlement path reject any message version other than legacy or 0 before inspecting signatures or instructions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The upto facilitator publishes extra.transactionVersions ([0]) in /supported, the server forwards it, the client fails fast with unsupported_transaction_version when version 0 is not advertised, and verifyOpenTransaction plus the upto settlement simulation reject any message version other than legacy or 0 before inspecting the instruction layout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…he version reason Facilitator-built upto settlements set a 1 MiB loadedAccountsDataSizeLimit, but the runtime counts the program-data account of every invoked program and mainnet Token-2022's is 1,382,061 bytes, so every mainnet Token-2022 claim, cancel or cleanup distribute would fail at the pre-broadcast simulation. Raise the default to 4 MiB and expose settleLoadedAccountsDataSizeLimit on the facilitator and rent-cleanup configs in TS and Go. The spec requires an open whose message version is outside the accepted set to be rejected with unsupported_transaction_version; both facilitators reported the generic open-transaction reason with the code buried in the message. Map the version-gate failure to the spec reason on verify and settle. Exercise the TS version gates with genuine transaction-v1 and legacy wire payloads now that the workspace resolves @solana/kit 8, instead of mocking the compiled-message decoder. Cap the rent-cleanup refetch at what the remaining transaction budget can carry. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the encoded wire - batch-settlement facilitators (TS, Go) advertise transactionVersions [0]; servers already forward the facilitator extra, and the batch clients fail closed with unsupported_transaction_version before building a deposit, top-up, or refund the facilitator cannot accept. Matches the merged spec. - facilitatorV1TransactionFits measures the fully serialized transaction, as Go does, with a test pinning the 4096/4097-byte boundary. - Go upto GetExtra advertises a copy of AdvertisedTransactionVersions. - Changeset calls out the @solana/kit >=8.0.0 peer floor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
62 reclaims sharing one fee and rent payer fill the 64 static-account budget of a v1 transaction within 4,096 bytes (matches pay-kit's calibrated MAX_RECLAIMS_PER_TX_V1). The packer still splits any batch that exceeds the wire, account, or instruction limits; v0 keeps its default of 8 and cap of 16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lockfile refresh replayed over a main that had moved on (axios bump), leaving examples/typescript/pnpm-lock.yaml without an axios@1.18.0 entry. Regenerate both from main's lockfiles plus this branch's package.json changes; e2e needs no changes on top of main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The e2e workspace links typescript/packages/mechanisms/svm, so its lockfile must record the raised @solana/kit, program-client and @solana-program specifiers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lgalabru
force-pushed
the
feat/svm-transaction-versions-upto
branch
from
October 26, 2026 21:30
a4ab86c to
64fe800
Compare
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.
Stacked on #16 (transaction-version negotiation for exact). This PR extends negotiation to
uptoand implements the facilitator-owned transaction behavior required by the upto SVM spec. It does not depend on #8.What changes
uptofacilitator advertisestransactionVersions: [0]; the client uses that only for its client-builtopentransaction and fails closed when v0 is unavailable.invalidReason/errorReasonunsupported_transaction_version, as the spec requires.computeUnitLimitandloadedAccountsDataSizeLimit; the existing microlamports/CU setting is converted to v1's total lamport priority fee.loadedAccountsDataSizeLimitdefaults to 4 MiB. The runtime counts the program-data account of every invoked program, and mainnet Token-2022's is 1,382,061 bytes (devnet's is 711,053), so a 1 MiB budget would have failed every mainnet Token-2022 claim at simulation. Operators can override it withsettleLoadedAccountsDataSizeLimiton the facilitator and rent-cleanup configs (TS and Go).@solana/kit8 encoder byte for byte.@solana/kit >=8andsolana-go v1.23, the first versions used here with transaction-v1 construction support. The TS version-gate tests now use genuine v1 and legacy wire payloads instead of mocking the decoder.Verification
gofmt,go vet ./...,golangci-lint run ./...(v2.7.2, 0 issues), andgo test ./...pass across the module.🤖 Generated with Claude Code