Skip to content

Latest commit

 

History

History
66 lines (54 loc) · 3.41 KB

mpp.md

File metadata and controls

66 lines (54 loc) · 3.41 KB

MPP

Experimental. Enable with payments.mpp.enabled: true.

The gateway targets draft-httpauth-payment-01, draft-payment-intent-charge-00, and draft-evm-charge-00 at tempoxyz/mpp-specs@806fdb8. It pins the pre-1.0 mppx@0.13.1 as an optional peer. For EIP-3009, the gateway follows mppx: it hashes JSON.stringify([id, realm]) with keccak256 to derive the nonce. The EVM draft instead hashes abi.encodePacked(id, realm). Credentials using the draft nonce, including those produced by mppx 0.12 or earlier, fail verification with wrong_nonce.

Later drafts or mppx releases may change the wire format again, so MPP remains experimental.

The implemented profile is charge intent, evm method and EIP-3009 authorization credential, using USDC on Base Sepolia or Base. The challenge is HMAC-bound to the resource and terms. It includes the canonical Permit2 address in methodDetails.permit2Address, as draft-evm-charge-00 requires for every credential type. The credential is verified locally, then checked by the x402 settlement provider. Both checks run in verify, before replay reservation; settlement broadcasts later.

For an HTTP request with a body, the challenge includes an RFC 9530 sha-256 digest of the original body bytes. The paid retry must send the same bytes: even equivalent JSON with different spacing returns body_digest_mismatch. MCP and A2A challenges omit the digest because their payment proof travels in the request body.

MPP and x402 derive the same replay identity for the same EIP-3009 authorization, so reuse across rails collides in one receipt store.

payments.mpp.paymentFlow takes the x402 flow values, but defaults to upfront: the payment settles before the backend runs. The charge intent forbids partial access before payment verification, which for the EVM method includes the transfer, and counts a backend call as partial access. Choosing authorization departs from that rule: the backend runs first, and a refused or unconfirmed settlement withholds its response but leaves its work unpaid. Under authorization, backend time also counts toward the challenge lifetime, challengeTtlSeconds (default 300), because mppx signs validBefore equal to the challenge's expires.

Over HTTP, the unpaid 402 and MPP verification, replay, settlement, and provider errors use application/problem+json and the core draft's problem types; the unpaid one is payment-required. Envelope members such as code, message, and details stay as extension members, and status is the numeric HTTP status. detail is a sentence; the reason token stays in message and details.reason. A successful Payment-Receipt includes challengeId and chainId.

A credential whose challenge already paid for a request is invalid-challenge with reason challenge_already_used. The gateway learns this from the facilitator's reason or the token's authorizationState. When neither shows it, including when that read fails, the facilitator's reason is reported instead, under verification-failed.

Terminate TLS in front of deployed MPP endpoints. The core draft forbids issuing challenges over plain HTTP.

Base mainnet deployments must satisfy the mainnet guardrails.

Unsupported variants are listed in src/payments/mpp/descriptor.ts: non-EVM methods, Permit2/transaction/hash credentials, splits, subscriptions, EVM sessions and the discovery extension.