test: add merchant checkout e2e; fix: drop Solana memo requirement#46
Conversation
Solana transactions no longer require a memo field. Removed memo handling from three locations: - PayWithSolanaToken: drop memo from the built paymentData - usePaymentState: drop memo from generateSolanaDeepLink for deposit addresses - WaitingDepositAddress: exclude SOLANA/SOLANA_USDT/SOLANA_USDC from the shouldShowMemo check (previously only BSC was excluded) Stellar, BSC, and other chain memo handling is untouched.
Merchant payments create a payId server-side via /payment-api/payments/merchant,
where the destination (chain/token/receiver) is fixed by the merchant config.
Tests only vary the source wallet, so this adds three source-only specs
(EVM/Solana/Stellar) that reuse the existing checkout pay-in helpers.
- helpers: add startMerchantCheckout() — POSTs the merchant order, feeds the
returned id into the checkout page's manual payId input, opens the modal
- env: add E2E.merchant config (appId gate, api url, amount_local/currency_local)
- specs: merchant/{evm,solana,stellar}.spec.ts, skipped unless E2E_MERCHANT_APP_ID
and the matching source wallet secret are set
- playwright.config + package.json: register merchant-{evm,solana,stellar} projects
- .env.e2e.example: document merchant vars
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 26f52027e1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…eporting in e2e tests - Updated playwright-core dependency from 1.60.0 to 1.61.1 in pnpm-lock.yaml and pnpm-workspace.yaml. - Added reportPayment function to helpers.ts for capturing payment summaries in Playwright reports. - Integrated reportPayment in merchant payment flow tests for EVM, Solana, and Stellar to ensure payId is reported after each test.
shawnmuggle
left a comment
There was a problem hiding this comment.
Review: LGTM ✅ (2-pass local review — Claude deep review + codex second opinion)
Verdict: no P0, no P1. Approving. 3 × P2 (non-blocking, follow-up).
Solana memo removal — verified safe (not a P0)
codex's second pass flagged 2 × P0 (PayWithSolanaToken, usePaymentState dropping memo → "memo-routed Solana orders become uncredited"). I traced the actual code and both P0s rest on the assumption that the backend reconciles Solana pay-ins by memo — which the code contradicts:
- Solana pay-in transfers to
hydratedOrder.intentAddr/order.intentAddr— a per-order unique deposit address. Reconciliation is by unique address + the explicittxHash+paymentIdreport to the backend (setPaymentCompleted/PAYMENT_SUBMITTED), not by on-chain memo. - The old memo was only an optional
Object.assignwhenhydratedOrder.memowas set; it never determined the destination or amount. - The diff correctly keeps memo for Stellar only (
Only Stellar needs a memo (destination tag)), because Stellar uses a shared address + memo to disambiguate orders. Solana uses unique addresses, so memo is redundant. This asymmetry is exactly right.
So the memo removal is the intended product change and is safe on the client side.
P2 (non-blocking follow-ups)
WaitingDepositAddressnull-option (underpaid-recovery) branch still builds the Solana deep link with memo and setsdepAddr.memo— the newshouldShowMemofilter only covers the selected-option branch (as codex-bot noted inline). Technically inconsistent but harmless: that branch also uses the uniqueorder.intentAddr. Worth a cleanup pass for full consistency.- Merchant Solana/Stellar E2E send
source: {chainId:"8453", tokenSymbol:"USDC"}(Base hint) but pay from Solana/Stellar, relying on the SDK to reconcile the real pay-in chain via/checkout. This matches your Reviewer Notes and is a valid test-design choice — but consider asserting the actual pay-in chain mid-test so a silent mis-route (Base pay-in over a Base-hinted merchant order) can't pass as green. - Backend confirmation: a pure client-side diff can't prove the Solana indexer never reads memo. Recommend a one-line confirmation from the backend side before merge that Solana settlement is unique-address-based.
Verified clean
reportPayment()only attaches payId/route/status/project — no wallet secrets in Playwright annotations/attachments.startMerchantCheckout(): solid error handling (res.ok check, missing-payId throw) and a real race-condition guard (waits for "Pay with Stellar" to prove the order hydrated).- Merchant
test:e2e:merchant-*scripts use--no-deps, so they don't cascade the real-funds dependency chain; all real-funds projects aretest.skip-gated on the wallet secret, so mocked CI never touches them. .env.e2e.example/env.tscontain placeholders only, no committed secrets.
Nice, well-scoped PR — clear commit split, honest Reviewer Notes, and the Stellar-vs-Solana memo asymmetry is handled correctly.
Summary
Adds end-to-end tests for merchant checkout payments and removes the memo requirement from Solana payment flows. Merchant payments create a
payIdserver-side (destination fixed by merchant config), so the tests only vary the source wallet and reuse the existing checkout pay-in helpers. Separately, Solana transactions no longer carry a memo, so memo handling is stripped from the three places it was still applied.Changes Made
Merchant e2e (
test)startMerchantCheckout()helper — POSTs to/payment-api/payments/merchant, feeds the returnedidinto the checkout page's manual-payId input, opens the modal. In-modal pay-in steps stay identical to Checkout.E2E.merchantconfig (appIdgate, api url,amount_local/currency_local), all env-overridable.merchant/{evm,solana,stellar}.spec.ts. Destination is server-fixed, so the 6-way source×dest matrix collapses to 3.merchant-{evm,solana,stellar}Playwright projects (chained into the sequential real-funds run before the deposit projects) and matchingtest:e2e:merchant-*scripts..env.e2e.example.Solana memo removal (
fix)PayWithSolanaToken: droppedmemofrom the builtpaymentData.usePaymentState: droppedmemofromgenerateSolanaDeepLinkfor deposit addresses.WaitingDepositAddress: excludedSOLANA/SOLANA_USDT/SOLANA_USDCfrom theshouldShowMemocheck (previously only BSC was excluded).Chore
.codegraph/.gitignoreto ignore all local codegraph data.pnpm-lock.yamlandbundle-analysis.html(build artifacts).How to Test
Merchant e2e (real funds, mainnet — opt-in):
cp examples/nextjs-app/.env.e2e.example .env.e2e, fill inE2E_MERCHANT_APP_ID(e.g.pos_rozostudio) plus the source wallet secret for the path you want.pnpm setup-wallets(EVM/Solana paths only).cd examples/nextjs-app && pnpm dev.pnpm test:e2e:merchant-evm(or-solana/-stellar).payId, pays it from the chosen source, and reaches Payment Completed.E2E_MERCHANT_APP_ID, confirm the merchant specs skip rather than fail.Solana memo (manual):
Typecheck:
cd examples/nextjs-app && pnpm typecheck(passes, exit 0). All three merchant projects list viaplaywright test --list.Testing Checklist
Reviewer Notes
source: {chainId:"8453", tokenSymbol:"USDC"}as the initial hint for all three specs (matching the reference cURL). When the user picks a different source token in-modal, the SDK reconciles the actual pay-in chain via the/checkoutAPI — so a Solana/Stellar pay-in over a Base-hinted order is handled correctly and needs no per-spec source override.E2E_MERCHANT_APP_ID+ the matching wallet secret, so CI'smockedproject never touches them.pnpm-lock.yaml/bundle-analysis.htmlare generated churn from a local connectkit rebuild — no intentional dependency change.