MPP - Charge Mode
| ID | Check Name | Spec Reference | What It Checks | Pass Criteria |
|---|---|---|---|---|
MPP-01 | Charge Settlement On-Chain | MPP Charge Guide; CAP-46 transfer events | The charge settles on-chain for exactly what the target advertised | The target's own 402 challenge is read first, unpaid, capturing the advertised amount (base units), currency and recipient. After payment, Stellar RPC getTransaction confirms the transaction referenced by the Payment-Receipt header succeeded, and its CAP-46 transfer contract event shows exactly one balance change: the advertised amount, to the advertised recipient, emitted by the advertised token contract, sent from this run's own payer. Verifying the event rather than the transaction envelope means a token contract whose transfer moves a different amount than its arguments claim is still caught. Verifying the sender means a target cannot satisfy the check by referencing some pre-existing transaction it did not cause. Verified against @stellar/mpp@0.7.1 — mode "pull" (default): onProgress only fires through "signed", so the settled tx reference comes from Payment-Receipt, not onProgress. |
Note on MPP-01's cost (Week 2). MPP-01 is not destructive: nothing is
permanently ended and the check can be run again. But it is not free and not
idempotent — every run settles a real payment from the payer key and moves
testnet funds, and repeated runs spend repeatedly. This is inherent to the check
rather than an implementation choice: charge mode has no dry-run, and a
settlement that did not happen cannot be verified on-chain. Both front ends say
so before running, and the MCP tool declares idempotentHint: false.
Settlement is read from Stellar RPC rather than Horizon, so the same endpoint
serves every MPP check and --rpc-url applies uniformly. The tradeoff is
retention: RPC keeps only recent history, so MPP-01 must verify a settlement it
just triggered, not an arbitrary past one. That matches how the check is used —
it pays, then verifies what it paid.
