feat(solana)!: route --chain solana through MPP solana/charge#17
Merged
vvillait88 merged 9 commits intomainfrom May 5, 2026
Merged
feat(solana)!: route --chain solana through MPP solana/charge#17vvillait88 merged 9 commits intomainfrom
vvillait88 merged 9 commits intomainfrom
Conversation
Pairs with agentscore/node-commerce#8 + agentscore/python-commerce#7 + agentscore/martin-estate#56. x402 Solana via @x402/svm omitted the idempotent ATA-create instruction in the buyer's SPL transfer tx, so payments failed against any payTo whose USDC ATA wasn't pre-warmed (every Stripe-multichain rotating address). Per upstream x402-foundation/x402#1020 ATA pre-creation is the seller's responsibility by design and won't be fixed in @x402/svm. MPP solana/charge bakes the createAssociatedTokenIdempotent instruction into the buyer's tx, so it works against any payTo. Changes: - Drop @x402/svm dep + ExactSvmScheme registration - Add @solana/mpp client peer dep - Route wallet.chain === 'solana' through payViaMpp (was payViaX402) - payViaMpp registers solanaCharge({signer, rpcUrl}) when wallet.chain is solana, tempo({account}) when wallet.chain is tempo - Protocol determination: 'x402' for base, 'mpp' for solana + tempo - payViaX402 throws unsupported_rail for non-base chains - All else unchanged (passport attach, max-spend, idempotency, retries, etc.) 352 tests pass. Architecture validated end-to-end against local martin-estate through the simulate step (broadcast deferred on devnet RPC reliability; not a code bug). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User-visible surfaces (CLI description in --help / --mcp / --llms, README rails table, agent-guide intro) were still claiming x402 on Solana via @x402/svm. Solana actually routes through MPP `solana/charge` via @solana/mpp/client; clarify that everywhere the user can see. - src/cli.ts:88 description: x402 on Base + Solana, MPP on Tempo -> x402 on Base, MPP on Tempo + Solana - README rails table: solana row now MPP `solana/charge` via mppx + @solana/mpp/client (was x402 SPL Token via @x402/svm) - src/commands/agent-guide.ts intro mirrors the new rail topology - .claude/CLAUDE.md chain-to-protocol routing maps `solana` to `solanaCharge` from @solana/mpp/client; drops ExactSvmScheme - tests/integration/README.md future-test description updated
Public-package source + README must describe behavior, not exact defense parameters or named-customer business domains. - README.md: drop the exact scrypt KDF parameters (`N=131072, r=8, p=1`) from the user-facing security note; the algorithm name is enough - src/commands/identity.ts: rate-limit retry suggestion no longer surfaces the "<= 1s" window granularity; points at the Retry-After header instead - src/commands/agent-guide.ts: regulated-commerce examples no longer name "wine" specifically; the regulated categories (age-restricted, jurisdiction- restricted, compliance-gated) are sufficient to convey the gating need
The `sessions create --context` describe text + the example block both used "wine purchase" as the canonical context value. Replace with a neutral "checkout" so the CLI manifest (visible to every LLM agent consuming `agentscore-pay --llms`) doesn't bake a customer's business domain into the public surface.
The Solana-rail explanation under ## Rails carried "the x402 SVM scheme had a known idempotent-ATA-create gap that the upstream maintainers won't fix". That's upstream finger-pointing in user-facing README copy. Replace with the factual statement (Solana payments use MPP `solana/charge` via the Solana Foundation package); the protocol choice stands without narration of the upstream gap.
The agent-guide note for `limits set` framed the local-only nature of the
limits in threat-model terms ("they protect against runaway agent loops,
not malicious merchants"). Restate as behavior-only: "the merchant cannot
read or override them."
The npm package description still claimed "x402 (Base, Solana) and MPP (Tempo)". Solana is MPP `solana/charge`, not x402, since 1.4. Match the README and cli.ts wording: "x402 (Base) and MPP (Tempo, Solana)."
Ships the cycle's pay changes (drop @x402/svm, route --chain solana through MPP `solana/charge` via @solana/mpp/client, dual-audience output updates, internal-disclosure scrubs) so the trusted-publishing workflow fires on tag push. Per pay versioning policy, pay stays on 0.X until coordinated launch.
vvillait88
added a commit
to agentscore/node-commerce
that referenced
this pull request
May 5, 2026
…fy+extraWarnings + x402scan discovery (#8) ## Summary Major release pulling together everything that landed on this branch beyond the original facilitator-error fix. Ships as `1.3.0` (next minor after `1.2.0`). **1. Kill x402 Solana, add MPP `solana/charge` (BREAKING)** - Drop `x402-solana-mainnet` / `x402-solana-devnet` rails from the registry. - Drop SVM from `validateX402NetworkConfig` (now base-only) and `verifyX402Request` (single `acceptedNetwork: string`, was `{base, svm}` object). - Drop SVM from `createX402Server` rail union; drop the SVM extraction branch in `extractPaymentSigner`. - Add `mpp-solana-mainnet` / `mpp-solana-devnet` rails (method=`solana`). - Add `solana` rail to `createMppxServer`, wiring `@solana/mpp/server` charge. - Drop `@x402/svm` from devDependencies; add `@solana/mpp` + `@solana/kit` as optional peer deps. - Cross-rename: `x402_solana` → `solana_mpp` field across challenge builders + discovery surfaces. **2. New helpers** - `classifyX402SettleResult` collapses `processX402Settle` failure phases (`verify_failed` / `settle_failed` / `facilitator_error` / `no_requirements`) to `(status, code, message, next_steps)`. Maps to 400 / 503 / 503 / 500. - `extraWarnings` field on `buildAgentInstructions` — append per-order warnings on top of the SDK's default protocol-footgun set. - Solana-network rejection branch in `verifyX402Request`: clients presenting an x402 credential on a `solana:*` network get a behavior-only hint pointing at the `solana/charge` rail. Case-insensitive prefix match. - `verifyX402Request` now wraps facilitator throws as `phase: 'facilitator_error'` cleanly across `build_requirements`, `enrich_extensions`, and `process_payment_request` steps. **3. Solana signer recovery in `extractPaymentSigner`** - New 3-step MPP recovery order: (a) EVM DID `did:pkh:eip155:<chain>:<addr>` source, (b) Solana DID `did:pkh:solana:<genesis>:<addr>` source, (c) pull-mode tx decode that reads the SPL `TransferChecked` authority via `@solana/kit` (optional peer). - Fixes the wallet-signer-match gap on Solana MPP: previously the recovered signer was always null on Solana credentials because `@solana/mpp/client` doesn't set `Credential.source`, which silently weakened wallet-auth security relative to EVM. Now the gate's `verifyWalletSignerMatch` enforces same-operator on Solana the same way it does on EVM. - Pull mode (`payload.type === 'transaction'`) covered. Push mode (`payload.type === 'signature'`) returns null (RPC fetch deferred; pay uses pull mode by default). - Defensive bounds-check on lookup-table account indices (v0 txs). **4. x402scan discovery (Layer 1)** - New `buildWellKnownX402` builder for the `/.well-known/x402` endpoint. - New OpenAPI extension helpers (`siwxSecurityScheme`, `xPaymentInfoExtension`, `xGuidanceExtension`). **5. Internal-disclosure cleanup** - Replaced threat-model rationale in source comments with behavior-only language across `core.ts`, `stripe-multichain/pi-cache.ts`, `payment/x402_validation.ts`, `signer-match.test.ts`. - Removed exact defense parameters from user-visible places. - Genericized customer-domain attributions baked into examples / docstrings / tests (Martin Estate / martinestate.com / wine-purchase → Example Merchant / agents.example.com / product-purchase). - Removed internal state name `pending_identity` from agent-visible warnings; agents see "the order will not complete." - Dropped upstream finger-pointing from README rails section. ## Test plan - [x] 660 vitest tests passing (4 skipped) - [x] eslint + typecheck clean - [x] CodeQL + dependency scan green ## Downstream impact Once this lands and `@agent-score/commerce@1.3.0` publishes: - `agentscore/martin-estate#56` will pass CI (currently red on `acceptedNetwork`, `extraWarnings`, `solana_mpp` RailKey). - `agentscore/pay#17` consumes the new SDK shape via the rails registry. - Solana wallet-signer-match enforcement turns on automatically for any martin-estate Solana settle. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mppx 0.6.14 → 0.6.15 typescript-eslint 8.59.1 → 8.59.2 Held back: - viem 2.48.7 (exact-pinned; 2.48.8 has a known regression) - eslint 9 → 10 + @eslint/js 9 → 10 (major-bump separate decision) Tests: 354 passing, lint + typecheck clean.
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
Pairs with agentscore/node-commerce#8 + agentscore/python-commerce#7 + agentscore/martin-estate#56.
`--chain solana` no longer registers `@x402/svm`'s `ExactSvmScheme`. It now registers `@solana/mpp/client`'s `charge` method on `Mppx` and pays via MPP `solana/charge`. Reason: `@x402/svm`'s tx-builder omits the idempotent `createAssociatedTokenAccount` instruction, so SPL transfers fail against any payTo whose USDC ATA isn't pre-warmed (every Stripe-multichain rotating deposit address). Upstream won't fix this per x402-foundation/x402#1020 (rent-drain attack vector).
Changes
Agent UX is identical: `agentscore-pay pay POST --chain solana ...` continues to work; pay handles the protocol switch transparently.
Test plan
🤖 Generated with Claude Code