SIGN IN SIGN UP

feat(checkout): surface the pool fee, complete the invoice lifecycle

The pool charges a flat 6 STRK per operation and documents it nowhere. The
widget now reads it from get_fee_amount(), adds it to the total before the
payer signs, and warns when it exceeds the invoice. Teaching MockWallet to
charge it broke ten tests that had been passing mainnet-impossible flows.

Payment correctness:
- Hosted page takes its amount from the merchant's watcher, not its own query
  string: an edited ?amount= used to produce a real "Paid" screen for a
  thousandth of the price. New unauthenticated GET /public/invoices/:id?to=
  serves invoice terms to whoever holds the link, and nobody else.
- Arcade INSERT COIN no longer tears down a checkout mid-payment: the money
  left, the credit never arrived, and the replacement invoice carried a new id
  so the duplicate guard never saw it either.
- Partial payments become underpaid (with shortfall) instead of expired, so
  their address is never released for reuse. Late ones become paid_late inside
  a 24h grace window instead of being dropped. Overpayment is reported.
- expiresAt in the past is refused at creation.

Merchant operations:
- Webhook queue persisted on the invoice row: a restart resumes deliveries
  rather than losing them. POST /invoices/:id/redeliver re-queues one.
- Idempotency-Key on POST /invoices, so a timed-out retry returns the invoice
  it already created instead of "already exists".
- GET /invoices.csv, with formula-injection-safe cells.

Widget and demos:
- Confirmation block before signing: merchant receives, pool fee, total,
  destination, network. Honesty panel moved above the button and opened.
- Explorer links come from the wallet, so mock hashes are not linked and
  sepolia does not link to mainnet Voyager.
- Wallet-missing message no longer tells you to update something you have not
  installed. Focus rings, 44px targets, reduced motion, touch controls, and
  keyboard capture that no longer steals Space from buttons.
- Landing page linking all three apps.

Packaging and tests:
- strk20-pay is publish-ready with a README, a React binding, and a full
  manifest. Publishing is the owner's to run.
- First automated tests for the widget, on a 120-line DOM double: 95 passing.
- server/dev-static.mjs sends no-store, because a cached module made three
  verification passes report the old code's behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
B
bongbongcrypto committed
a069dc4fdf10eb2fb0df88aadded604ef617d521
Parent: bd2af8a