Skip to content

PR 10 — E2E crypto smoke: Base Sepolia → Stellar testnet round-trip + runbook #146

@0xdevcollins

Description

@0xdevcollins

Why

We shipped the full CCTP V2 customer pay flow in PR #136 — endpoints, BullMQ worker, frontend rewrite, settlement wallet auto-provisioning. The code paths are exercised by unit tests (202 passing) and by curl smokes against the API. What hasn't happened: a real testnet USDC burn → attestation → mint round-trip.

Until that happens, "the crypto flow works" is a promise. This issue closes that gap.

Scope

Two deliverables:

  1. Do the round-trip manually. Burn real testnet USDC on Base Sepolia through the checkout app, watch the worker drive it through PROCESSING → COMPLETED, confirm the USDC lands on the merchant's Stellar testnet address.
  2. Write a runbook at `apps/api/docs/operations/crypto-e2e-smoke.md` so anyone on the team can rerun this in 15 minutes.

What you need before you start

Source side (customer wallet)

Destination side (merchant settlement wallet)

  • New merchants auto-provision a Stellar testnet wallet at signup (PR Phase 1: hosted checkout, CCTP V2 cutover, managed Stellar settlement #136). The wallet:
    • Is funded by Friendbot (10k XLM testnet)
    • Has a USDC trustline already opened (testnet issuer `GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5`)
    • Mirror address is on `merchant.settlementAddress`
  • So all you need to do is register a new merchant and the destination side is ready.

Local stack

  • API on :3333 (`npm run start:api` from repo root)
  • Checkout on :3003 (`npm run dev:checkout`)
  • Dashboard on :3001 (`npm run dev:dashboard`)
  • Postgres + Redis via `docker compose up -d`
  • `apps/api/.env` has `STELLAR_NETWORK=testnet` and a real `SETTLEMENT_KEY_KEK` (any 32-byte hex)

The test flow

  1. Register a fresh merchant at `http://localhost:3001/signup\` (use a throwaway email like `smoke+$(date +%s)@example.com`)
  2. Confirm the wallet provisioned: `http://localhost:3001/settings\` → "Settlement wallet" card shows green "Settlement active" with a G… address. Copy it.
  3. Verify the destination is real on Stellar: https://stellar.expert/explorer/testnet/account/G… → account exists, has a USDC trustline
  4. Create a payment link: dashboard `/links` (or via curl if PR PR 8 — Dashboard: /links list page + create-link form #144 isn't merged yet)
  5. Open the link in an incognito browser: `http://localhost:3003/l/`
  6. Click Pay → land on `/[paymentId]`
  7. Click "Pay with Crypto" → `/[paymentId]/crypto`
  8. Connect MetaMask → switch to Base Sepolia when prompted
  9. Pick "Base" (default) → click "Lock quote" → wallet switches network if needed, shows quote (~25 USDC → ~24.875 USDC after 0.5% fee)
  10. Click "Approve & Pay X USDC" → MetaMask prompts twice:
    • First: `approve(TokenMessengerV2, amount)` on USDC contract — confirm
    • Second: `depositForBurnWithHook(...)` on TokenMessengerV2 — confirm
  11. Watch the progress card: "Approve USDC spend" → "Burn on source chain" → "Circle attestation" → "Mint on Stellar" stages
  12. Expected timing: ~30s for the burn tx to confirm on Base Sepolia, then ~8–20s for Circle's Iris attestation, then ~5s for the Forwarder Service mint
  13. On success: page redirects to `/[paymentId]/success` with green check + "View settlement on Stellar" link
  14. Verify on Stellar: stellar.expert link from the success page → see the USDC mint operation crediting the merchant's address

Where it'll probably break (and how to debug)

Failure Likely cause Where to look
502 from `/select-crypto`: "Merchant has not configured a Stellar settlement address" Auto-provisioning failed at signup (Horizon was down). Click "Provision settlement wallet" on `/settings` to retry. Settlement card on /settings
Approve tx succeeds, burn tx fails with revert Wrong USDC contract address; check `apps/api/src/modules/cctp/contracts.ts` `USDC_ADDRESSES.base.testnet` matches Circle's published address Tx detail on basescan.org
Burn confirms, status stays SOURCE_LOCKED forever Worker can't reach Iris OR didn't get enqueued. Check: `/readyz` for circle probe; BullMQ dashboard for the `cctp.observe` queue; `docker logs` for Redis API log
PROCESSING but never COMPLETED Forwarder Service didn't broadcast the mint. Could be: hook data malformed (decode it via Stellar Lab), merchant Stellar address has no USDC trustline, Iris reports `forwardTxHash` is null. API log + Iris response in worker logs
Mint reverts on Stellar Settlement address has no trustline. Should never happen with the new auto-provisioning, but if it does, check `MerchantSettlementKey` row + Stellar account ops history. stellar.expert

Runbook deliverable

Write `apps/api/docs/operations/crypto-e2e-smoke.md` with:

  • All of the above (prereqs, flow, debug tips), shaped as a copy-paste-able checklist
  • Screenshots at key steps (link page, method picker, wallet prompts, success page, Stellar Lab USDC arrival)
  • A bash script in the doc: "register a fresh merchant + create a link + print the test URL" so the next runner doesn't have to assemble it
  • Expected timing per step, so anomalies are obvious

Acceptance criteria

  • Successfully completed one full burn → mint round-trip with real testnet USDC
  • Source tx hash recorded in `Payment.sourceTxHash`
  • `cctpNonce` and `cctpAttestation` populated by the worker
  • Destination tx hash recorded in `Payment.destTxHash`
  • Final status = COMPLETED
  • Stellar Lab / stellar.expert shows the USDC mint operation on the merchant's account
  • Webhook fires `payment.completed` (verify via webhook.site or local listener)
  • Runbook MD lands in `apps/api/docs/operations/` with screenshots
  • Add the runbook to the on-call doc index

Estimated effort

~0.5 day if the stack is up and faucets cooperate. Could blow up to 1 day if you hit a real bug — but finding bugs is the point.

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendBackend API workcritical-pathBlocks other workdocumentationImprovements or additions to documentationstellarStellar blockchain integration

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions