Skip to main content
Consolidated from the 2026-07-28 production-readiness audit and subsequent work. Fixed items are in Status.

Blocking

supabase db reset and npx supabase test db fail: migration 20260529090000 references public.rate_limits before any migration creates it. Two duplicate version timestamps were fixed, but that was only the first blocker.Production tracks 86 migrations and does not record the local colliding versions. The pgTAP test supabase/tests/quotes_anon_write_lockout.sql cannot run until this is repaired.Consequence: no local reproduction of the production schema, and no database tests.
A launch blocker independent of the audit and legal gates. Needs funding plus low-balance alerting, and — once merchants bear sweep gas — a native-gas inventory buffer sized to expected monthly spend.
423,918 / 451,643 / 495,529 across three different issues, and one reports a cloned sweep at 24,988 against the original’s 54,383. A proxy cannot make an identical sweep cheaper — the hop only adds. Either the sweep logic changed between measurements or they were taken on different harnesses.Consequence: the break-even floor, the reimbursement ledger, and the per-customer crossover all rest on a number nobody has pinned. Re-measure the same logic both ways on one harness.
Does TRON’s Dynamic Energy Model attribute delegatecall energy to the implementation or the proxy? TIP-491’s worked example uses CALL, and neither the TIP nor the docs resolve it.Consequence: blocks the per-customer forwarder design. The decision is irreversible once proxies are deployed.

Correctness

Two compounding errors: the cost basis assumes 230,000 gas against a measured 495,529, and the floor is set equal to the gas cost rather than divided by the take rate. A 0.30Ethereumorderearns0.30 Ethereum order earns 0.00225 against $0.139 of gas.Also fails open to 0 for an unknown chain, which for an economics gate means quoting a guaranteed loss.
WATCH_STATUSES in pool-indexer-poll omits swept and settled. Once an intent terminalises, its forwarder stops being watched forever — no event, no status change, no webhook, nothing on any dashboard. Funds are recoverable because the forwarder is re-callable, but nothing surfaces them.
Capture on the connect rail is defined as the deposit confirmation, but the embed’s payment_confirmed event and the done state gate on the subsequent keeper sweep. The UX is stricter than the policy, delaying the merchant’s completion signal.
With refund() removed, a partial payment sits in a forwarder with no way to complete or return it without manual intervention. Needs a customer top-up prompt plus a merchant sweep-and-refund action.
A post-expiry arrival is settled at the original quoted amount with no time limit, however stale. The locked decision is to re-quote at the current rate and re-check the tolerance band.
Encoded as 0x09, which is V2’s opcode. Requires a redeploy. Phase 2 only, so not currently on the default path — but do not build on payWithSwap.

Visibility and trust surfaces

Plus incomplete partner-visible merchants RLS. Beyond the dashboard bug, this means a regression in the partner’s 0.25% share would be invisible — which is why fee changes need an explicit regression test.
A 'none' secret option exists, and test and live signatures do not match.
The client-side trust guarantee does not extend to TRON. Any statement about routing non-custody must be scoped to EVM.
Default-recipient merchants and the atomic rail are a separately tracked gap. The go-live attestation gate for that rail is open.

Documented and accepted

  • paymentId replay keyed on paymentId alone, not (merchant, paymentId). Infeasible to exploit at 128 bits of randomness (~2⁻⁶⁴). Deferred to a future redeploy.
  • TRON keeper drops expired intents.
  • Two flaky testsApp.test.tsx, LandingFooter — pass in isolation.
  • Chunk-size build warnings are pre-existing.

Landmines

Things that are not bugs but will bite.