feat(commerce 1.3)!: kill x402 Solana, add MPP solana/charge + classify+extra_warnings + x402scan discovery#7
Merged
vvillait88 merged 12 commits intomainfrom May 5, 2026
Conversation
…_result Mirrors agentscore/node-commerce#8 in python-commerce. Adds a fourth phase to ProcessX402SettleFailure: 'facilitator_error'. The verify-stage calls (build_payment_requirements, enrich_extensions, process_payment_request) are now wrapped in try/except. A facilitator that raises (e.g. CDP rejecting solana:devnet because it only supports mainnet) returns phase='facilitator_error' with a 'step' field instead of bubbling up as an opaque 500. settle_failed semantics preserved. Adds classify_x402_settle_result(result) that maps the tagged result to a ClassifiedX402Error envelope with controlled status/code/message/next_steps: verify_failed -> 400 payment_proof_invalid / regenerate_payment_credential facilitator_error -> 503 payment_provider_unavailable / try_different_rail settle_failed -> 503 payment_provider_unavailable / retry_or_swap_method (retry_after_seconds: 10) no_requirements -> 500 payment_internal_error / contact_support The returned envelope is intentionally facilitator-agnostic and never carries raw error detail; merchants log result server-side and return the classified envelope to the consumer. Updates README drop-in example to use the helper. Bumps to 1.3.0. 708 tests pass at 95.46% coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t-info, x-guidance, siwx) Mirrors agentscore/node-commerce@01010df. - build_well_known_x402(): emits {version: 1, resources: ["METHOD /path"]} for /.well-known/x402 - x_payment_info_extension(): per-operation x-payment-info with fixed/dynamic price + protocols - x_guidance_extension(): info.x-guidance prose blob - siwx_security_scheme(): http bearer SIWX entry - agentscore_security_schemes() now includes siwx alongside OperatorToken + WalletAddress - /.well-known/x402 added to DEFAULT_DISCOVERY_PATHS Smoke verified: spun up a stdlib http.server emitting all the new docs and ran @agentcash/discovery against it. Output identical to the node smoke: Source: openapi Routes: 3 POST /purchase paid 0.10 USD [x402, mpp] POST /quote paid 0.01-5.00 USD [x402] GET /whoami siwx Guidance: 29 tokens 716 tests pass at 95.52% coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors agentscore/node-commerce@32ea663. Drops x402-Solana from python-commerce since the upstream x402[svm] Python lib has the same InvalidAccountData problem and no Python equivalent of @solana/mpp exists yet (pympp extras are [server, tempo, stripe, redis, sqlite] — no solana). So python-commerce drops x402 Solana for parity but does NOT add MPP Solana server-side wiring. The accepted_methods / how_to_pay builders still emit the solana/charge JSON shape so an agent-side @solana/mpp/client buyer can pay; Python merchants must implement server-side verification themselves until a Python lib ships. Changes (BREAKING): - Drop x402-solana-* rails, drop SVM from validation + x402_server - validate_x402_network_config is now base-only; drop svm_network field - verify_x402_request takes accepted_network: str (not {base, svm}) - Drop is_solana from VerifyX402RequestSuccess - Rename x402_solana -> solana_mpp field in challenge builders + discovery - Add mpp-solana-* rails to the registry - Drop svm extra from x402 peer dep group - Bump 1.3.0 -> 1.4.0 713 tests pass at 95.56% coverage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
…c cleanup The 1.4.0 kill-x402-Solana commit renamed the public exports in challenge/__init__.py but missed the underlying class definitions and some example/test usages. This catches the gap so examples actually import. Renames: - accepted_methods.X402SolanaConfig -> SolanaMppConfig - how_to_pay.X402SolanaRailConfig -> SolanaMppRailConfig - BuildAcceptedMethodsInput.solana_mpp now typed SolanaMppConfig - HowToPayRails.solana_mpp now typed SolanaMppRailConfig - examples/multi_rail_merchant.py + tests catch up to the rename Other doc cleanup: - examples/api_provider.py drops the dead x402 Solana accepts entry + the stale x402_svm_rail variable; advertises Solana via MPP rail directives in the WWW-Authenticate header (same path tempo uses) - examples/multi_rail_merchant.py drops the dead `verified.is_solana` property (no longer on VerifyX402RequestSuccess); test-mode simulate now hardcoded to `network="base"` since x402 verify only runs on base - identity/signer.py docstring clarifies Solana now goes through MPP (not x402), so this helper returns None for Solana payloads - CLAUDE.md updates the api_provider description + drops `x402[evm,svm]` references (the upstream extra is gone; we depend on `x402[evm]`)
…gs hook verify_x402_request gets a dedicated branch for incoming x402 credentials on a solana:* network. Instead of the generic "Unsupported x402 network" message, the response points the client at the `solana/charge` rail in the 402 challenge so an agent on a stale x402 SVM client can recover with one re-sign. Both the error message and next_steps stay behavior-only: no internal terminology, no CLI vendor references, no protocol-handshake mechanics, no infra disclosure. build_agent_instructions gets an `extra_warnings` field so merchants can append per-order rail-availability notes on top of the SDK's protocol-footgun defaults (without overriding them). Set `warnings` directly to override entirely; `extra_warnings` is ignored in that case. - agentscore_commerce/payment/x402_validation.py: new solana:* branch in the network-mismatch check - agentscore_commerce/challenge/agent_instructions.py: BuildAgentInstructionsInput gets `extra_warnings`; default-warnings concat covers both rails + extras - tests/test_lifted_helpers.py: assertion updated for the new Solana hint - tests/test_challenge.py: two new tests for extra_warnings + the override case
Mirrors the node-commerce sweep on the python side: - Removed "pending_identity" (internal order-state column value) from _TEMPO_WARNING + _X402_WARNING in agent_instructions.py and from the default llms.txt template; agents see "the order will not complete" - Tightened the agentscore-pay tool description from "x402 on Base + Solana" to "x402 on Base and MPP on Tempo + Solana" so the rail-protocol mapping matches the 1.4.0 reality (Solana goes through MPP solana/charge) - Genericized docstring examples in identity/a2a.py, identity/ucp.py, discovery/skill_md.py, challenge/order_receipt.py: "Martin Estate" + "agents.martinestate.com" + "wine-purchase" placeholders replaced with "Example Merchant" / "agents.example.com" / generic skills - examples/multi_rail_merchant.py docstring renamed from "Martin-Estate- style" to "regulated-commerce" to describe the pattern, not the customer Mintlify worked-example pages keep referencing Martin Estate by name; that's allowed at the marketing/URL level per the disclosure-posture rules.
Public-package tests are part of the public surface (visible on the PyPI sdist + GitHub source). The sessions / a2a / ucp / skill_md tests were using "Martin Estate" / "https://agents.martinestate.com" / "martin-estate- wine-commerce" as fixture values; that bakes a public reference customer's domain into the SDK source. Swap to "Example Merchant" / "agents.example.com" / "example-merchant-commerce".
…string
Replace "Prevents agents from sending payment to an attacker-controlled
address and replaying the credential" with the behavior-only equivalent
("Validates the credential's deposit address against the addresses the
merchant has actually minted"). Mirrors the node-commerce pi-cache.ts
sweep.
…pi comment
The _CANONICAL_AGENTSCORE_API note explained why the URL was hardcoded in
threat-model terms ("Prevents a malicious merchant from emitting memory
pointing agents at their own phishing endpoints"). Behavior-only language
is enough; the canonical-URL choice stands without narrating the threat.
Lands the cycle's commerce SDK changes (kill x402 Solana + add MPP solana/charge + classify+extra_warnings + x402scan discovery + internal- disclosure scrubs) as the next minor release after 1.2.0.
…2_request
Mirrors the node-commerce defensive fix: `.lower().startswith('solana:')`
catches malformed credentials carrying uppercase or mixed-case CAIP-2
prefixes and routes them to the targeted Solana hint instead of the
generic 'Unsupported x402 network' fallback.
vvillait88
added a commit
to agentscore/pay
that referenced
this pull request
May 5, 2026
## 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 - Drop \`@x402/svm\` dep - Add \`@solana/mpp\` client peer dep - \`wallet.chain === 'solana'\` now goes through \`payViaMpp\` (was \`payViaX402\`) - \`payViaMpp\` registers \`solanaCharge({signer, rpcUrl})\` for Solana wallets, \`tempo({account})\` for Tempo - \`Protocol\` is \`'x402'\` for base, \`'mpp'\` for Solana + Tempo - \`payViaX402\` throws \`unsupported_rail\` for non-base chains - Everything else unchanged (passport attach, \`--max-spend\`, idempotency, retries, dry-run) Agent UX is identical: \`agentscore-pay pay POST <url> --chain solana ...\` continues to work; pay handles the protocol switch transparently. ## Test plan - [x] 352 tests pass (vitest) - [x] Local dry-run shows \`protocol: mpp\` for \`--chain solana\` - [x] Local live-run reaches simulate against martin-estate (broadcast deferred on devnet RPC reliability) - [ ] On-chain settle smoke (mainnet or alternate devnet RPC) - [ ] Coordinate release with martin-estate#56 deploy + new \`@agent-score/pay\` rc tag 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sentry-sdk 2.58.0 → 2.59.0 types-requests 2.33.0.20260408 → 2.33.0.20260503 Plus 5 transitive packages dropped from the lockfile (no longer reachable from the resolved deps): construct, construct-typing, jsonalias, solana, solders. Tests: 715 passing, ruff + ty 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
Mirrors
agentscore/node-commerce#8on the Python side. Ships as1.3.0(next minor after1.2.0).1. Kill x402 Solana (BREAKING)
x402-solana-*rails. Addmpp-solana-*rails (method=solana).validate_x402_network_confignow base-only (base_network: str, was{base, svm}object).verify_x402_requesttakes singleaccepted_network: str.X402SolanaConfig→SolanaMppConfig,X402SolanaRailConfig→SolanaMppRailConfig.x402[evm,fastapi]>=2.8,<3(nosvmextra).@solana/mpp, socreate_mppx_serverdoes not ship a Solana rail. Python merchants on Solana implement MPPsolana/chargeserver-side themselves.2. New helpers
classify_x402_settle_resultcollapsesprocess_x402_settlefailure phases (verify_failed/settle_failed/facilitator_error/no_requirements) to(status, code, message, next_steps). Mapping is identical to the node side: 400 / 503 / 503 / 500.extra_warningsfield onBuildAgentInstructionsInput; append per-order warnings on top of defaults.verify_x402_request: clients presenting an x402 credential on asolana:*network get a behavior-only hint pointing at thesolana/chargerail.process_x402_settlewraps facilitator throws asphase='facilitator_error'across all steps.3. x402scan discovery (Layer 1)
build_well_known_x402builder.siwx_security_scheme,x_payment_info_extension,x_guidance_extension).4. Internal-disclosure cleanup
stripe_multichain/pi_cache.py,identity/types.py,identity/signer.py).pending_identityinternal state name from agent-visible warnings.x402[evm,svm]references from CLAUDE.md (the upstream extra is gone; we depend onx402[evm]).Test plan
Downstream impact
Once this lands and
agentscore-commerce==1.3.0publishes:agentscore/core#230will pass CI (currently red onagentscore-commerce[mppx,x402]>=1.3.0resolution).verify_x402_request+process_x402_settle+classify_x402_settle_resultwiring depends on this SDK release.🤖 Generated with Claude Code