Skip to content

Donate layout + SOL-only UI; P0 receipt/verify harden - #3

Draft
gregrdev wants to merge 2 commits into
mainfrom
cursor/donate-layout-p0-verify-a9f2
Draft

gregrdev wants to merge 2 commits into
mainfrom
cursor/donate-layout-p0-verify-a9f2

Conversation

@gregrdev

@gregrdev gregrdev commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Summary

PR #3 (does not touch PR #1 / cursor/agent-ux-musts-e117).

(A) /donate layout + SOL-only

  • Stack human tip full-width, then the agent panel, until xl (gap-6 xl:grid-cols-2). Removes the early lg two-column that clipped curl and cramped tip cards at ~1280 and trapped horizontal scroll at ~390.
  • pre/curl: min-w-0 max-w-full overflow-x-auto whitespace-pre text-xs.
  • Signature field: min-w-0 w-full, placeholder Paste base58 tx signature, helper for Phantom / Explorer.
  • Tip cards: grid-cols-1 gap-3 p-4; labels wrap instead of colliding with amounts.
  • Receipt box Mood A quiet: border-border bg-surface.
  • Dropped the USDC toggle on donate. Verify is native SOL (onchain-sol) only; copy states USDC is not receipt-eligible. Receive/practice USDC is unchanged.

(B) P0 security / Protocol CLEAR

  1. Receipt payer = on-chain fee payer only (resolveReceiptPayer). Client payload.payer is never credited; mismatch rejects.
  2. Instruction-level SystemProgram transfer / transferWithSeed to payTo. Balance-delta alone does not credit. Missing blockTime fails closed.
  3. Durable single-use sig store (Upstash/Vercel KV SET NX, else filesystem O_EXCL). Not process-local creditedSignatures. Fail-closed if the store cannot claim.
  4. Unified address validators: canonical PublicKey + on-curve wallet for donate payTo. Regex-only API gate removed.
  5. encodeSolanaPayUrl validates recipient as a canonical public key.
  6. check-402 isPrivateIp: ::ffff: mapped IPv4 (the old :ffff: prefix never matched). Unrecognised forms fail closed.
  7. Lab exact-lab: Number.isFinite(timestamp) before the age window; optional payTo bind in the signed message when the challenge advertises it. Framing stays educational exact-lab ≠ facilitator exact USDC. Lab nonces remain process-local (labeled).
  8. Create-wallet last-6 confirm is exact case (base58 is case-sensitive).

(P1 follow-up) CORS Access-Control-Expose-Headers

  • Lab + donate OPTIONS and JSON (including 402) now expose PAYMENT-REQUIRED and Payment-Required in addition to the existing X-PAYMENT-RESPONSE / PAYMENT-RESPONSE twins, so browser JS can read the challenge header. Other CORS allow-origin / allow-headers unchanged.

Out of scope: dead auth/db/multiplayer delete; Home/gloss Mood A on PR #1; donation address/economics copy.

Production note

Donation receipts need a durable replay store. Set KV_REST_API_URL + KV_REST_API_TOKEN (or Upstash equivalents) on Vercel. Local/dev uses data/credited-donation-sigs/ (gitignored).

Tests

npm run test:p0 — mapped IPv4, address gate vs regex, Solana Pay recipient, instruction bind, client payer mismatch, lab timestamp/payTo, filesystem single-use claim, CORS expose list includes Payment-Required twins.

Hypothesis (confirmed)

lg:grid-cols-2 was too early; donate API preferred proof.payload.payer over result.payer. Both are fixed.

Open in Web Open in Cursor 

Stack human tip then agent panel until xl, SOL-only Solana Pay (USDC is
not receipt-eligible), and make curl/signature fields scroll instead of
clip. Receipt payer is the on-chain fee payer only; verify requires a
SystemProgram transfer to payTo, fail-closed blockTime, and a durable
single-use signature store. Shared PublicKey address checks, Solana Pay
recipient validation, ::ffff: SSRF mapping, lab finite timestamps +
optional payTo bind, and exact-case wallet confirm.

Co-authored-by: Phoenix <grachkovsky@gmail.com>
@vercel

vercel Bot commented Sep 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
shipx402 Ready Ready Preview Sep 16, 2026 6:51am UTC

Request Review

Browser JS cannot read the 402 challenge header unless it is listed in
Access-Control-Expose-Headers. Add PAYMENT-REQUIRED and Payment-Required
alongside the existing response twins on OPTIONS and JSON responses.

Co-authored-by: Phoenix <grachkovsky@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants