feat(x402-solana): package the signer + full MCP verify/settle e2e (Beta on devnet)#32
Merged
tkorkmazeth merged 3 commits intoJun 25, 2026
Conversation
…eta on devnet) Moves Solana from "experimental rail + example" to a packaged, end-to-end Beta. - Ship the client signer in the package: src/rail-adapters/x402-solana-signer.ts exports buildSolanaPaymentPayload + extractSolanaRequirement (also re-exported from the root). @solana/web3.js and @solana/spl-token become OPTIONAL peer dependencies, dynamically imported — install stays light for non-Solana callers. The example sign-payload.mjs now re-exports from the package. - Add src/__tests__/x402-solana-e2e.test.mjs: drives the MCP adapter's built-in verify -> credit -> execute -> settle path on the Solana rail against a fake in-process facilitator (localhost; no validator). Asserts the 402 Solana challenge, the signed retry, and a trace carrying rail_payment_verified + rail_payment_settled with the on-chain tx signature. - Status bumped Experimental -> Beta on devnet (README + landing). Mainnet still untested. Full suite: 230 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mainnet) devnet-settle.mjs now honors SOLANA_NETWORK=devnet|mainnet (plus NETWORK_CAIP2 / USDC_MINT / SOLANA_RPC_URL overrides), resolving the CAIP-2 id, USDC mint, default RPC, and explorer cluster per network. Mainnet uses a real-USDC funding prompt instead of the faucet. Self-transfer default keeps the smoke test zero-net-cost. Gitignore the mainnet payer keypair too. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ran the same flow on Solana mainnet-beta with real USDC via PayAI: self-transfer, err: None, fee paid by the facilitator (tx 3d9k5PACqnSqYk42xMjyvkdzZZNfDPjysRyHGVzpxxCYu1womD6eMAGQx2neZcNCerLNkbjDoy15Y31...). Status (README + landing): Solana x402 now "Beta; verified on devnet and mainnet". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tkorkmazeth
pushed a commit
that referenced
this pull request
Jun 25, 2026
When a payment is verified + executed but settlement fails after the fact
(facilitator/RPC blip), it was a dead-end trace (settlement_uncertain) with the
provider unpaid. Phase B turns that into a recovery loop:
- src/settlement-recovery.ts:
- settleWithRetry() — bounded exponential backoff over settlePayment.
- PendingSettlementStore + InMemoryPendingSettlementStore — durable queue of
verified-but-unsettled payments.
- SettlementReconciler — drains the queue through each rail adapter; removes
what settles, keeps the rest with attempts/lastError for the next pass.
- TollGate: pendingSettlementStore config (default in-memory), `pendingSettlements`
getter, `enqueueSettlement()`, and `reconcileSettlements(opts)`.
- MCP adapter: settle now retries (configurable via settleRetry); anything still
unconfirmed is queued and the trace records attempts + queued:true.
Tests (src/__tests__/settlement-recovery.test.mjs): retry success/exhaustion,
store ops, reconciler drain/keep/no-adapter, and an end-to-end loop through
TollGate + the MCP adapter (settle fails -> queued -> reconciled).
Built on the merged Solana Beta (#32) and EVM EIP-712 (#33) work. Full suite: 242 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Phase A of hardening Solana: move it from experimental rail + example to a packaged, end-to-end Beta.
Signer ships in the package
src/rail-adapters/x402-solana-signer.tsexportsbuildSolanaPaymentPayload+extractSolanaRequirement, re-exported from the root:@solana/web3.jsand@solana/spl-tokenare now optional peer dependencies, dynamically imported — installs stay light for callers that never sign on Solana. The examplesign-payload.mjsre-exports from the package (one implementation).Full MCP verify→settle e2e (CI, no validator)
src/__tests__/x402-solana-e2e.test.mjsdrives the MCP adapter's built-in verify → credit → execute → settle path on the Solana rail against a fake in-process facilitator (localhost/supported,/verify,/settle)._meta(network, mint, discoveredfeePayer), signed retry, premium execution, and a trace carryingrail_payment_verified+rail_payment_settledwith the on-chain tx signature.Status
x402 — Solana / SVMbumped Experimental → Beta on devnet. Mainnet still untested.Full suite: 230 passing, typecheck clean.
Follow-ups (next phases)
🤖 Generated with Claude Code