Repository navigation
Conversation
|
@Ugasutun Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Coordination note — ten PRs are editing one 179-line fileIf your MCP PR has just gone red with a conflict, this is why, and it is my fault rather than yours. I published 22 MCP issues (#404–#425) as if they were independent. They are not: almost all of them land in Already merged:
Order I intend to take the rest in, so you can rebase once rather than repeatedly:
Please do not all rebase at once. If you are below the one currently in flight, wait until the one above you lands — otherwise you rebase, I merge someone else, and you rebase again. I will comment on your PR when it is your turn. One thing to settle between you: Nothing here reflects on the quality of the work. Several of these are among the best PRs this repo has had. |
|
#487 has landed — the I resolved #487's conflicts myself because nine PRs were stuck behind it. Three things on 1. Two refusal codes, deliberately separate. ERR_URL_BLOCKED // the target resolves somewhere we will never fetch (#488)
ERR_HOST_NOT_ALLOWED // reachable, but not on the paid_call allow-list (#487)If your PR adds a refusal, extend this vocabulary rather than starting a third. "I cannot reach there" and "I will not pay there" are different answers; whatever you add should be a third distinct answer, not a synonym for one of these. 2. The constructor takes 3. Push the rebase and I will review it. If it conflicts in a way that is not obvious, say so and I will resolve it rather than leave you stuck. |
c6f0249 to
a9b314e
Compare
Closes #423
Summary
The only 402 test asserted that a rejected payment maps to
ERR_PAYMENT_REJECTED. The successful path (construct, sign, submit, returnthe resource) had no coverage, even though it is the path that moves money and
the one most likely to break silently on an x402 or Stellar SDK upgrade. This
PR adds a deterministic end-to-end test of the full 402 loop against a local
stub that demands payment and verifies it. No mainnet, no real keys, no
network access.
Changes
402with payment requirements(amount,
payTo, network) and, on a retried request carrying a paymentheader, verifies the payload through a fake facilitator before returning
200with the resource.payload and records exactly what it received, so tests can assert on the
signed contents rather than just the response body.
(
Keypair.random()orcreateEd25519Signerwith a generated secret). Nosecret is committed, no fixture key is used, and no real account is
referenced.
127.0.0.1on an ephemeral port, so the test needs noexternal network access and cannot collide with other runs.
the expired-signature case is deterministic.
What is asserted
Successful loop:
402; the client retries exactly once with apayment header; the final response is
200with the expected body.payTo), comparedagainst the stub's configured account, so paying the wrong account fails
the test.
(testnet passphrase,
stellar:testnet).Failure branches:
for. The client refuses, and the facilitator receives no payment.
window has passed. The call surfaces
ERR_PAYMENT_REJECTED, not a body.maxPrice: the stub demands more thanmaxPrice. Theclient refuses to sign, and the assertion checks that nothing was signed
or submitted (the fake facilitator recorded zero payments).
ERR_PAYMENT_REJECTEDmapping is keptand now exercised through the same harness.
Why this matters for the SDK upgrade
The repo pins
@stellar/stellar-sdkfour majors behind current. Because theassertions inspect the signed payload (amount, destination, passphrase), an
SDK or x402 upgrade that changes encoding, defaults or network handling will
fail this test instead of passing silently while paying the wrong account.
Determinism and safety
test and discarded.
MCP_MAX_PAYMENT_PRICEexplicitly rather than relying onthe default.
Checklist
maxPriceis refused, asserted