Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,36 @@ publicKey}`), and `verifyNep413` for the JSON/RAAT convention that no wallet pro
- 🔍 still unverified: one real end-to-end login against a live wallet (the byte layout is the library's,
the _dialog_ — what a wallet shows the human — is not testable offline).

### Answered: does Settle need testnet for anything? (S7.14, 2026-11-10)

**No. No judged path can run on testnet, and one path would break silently if it did.**

Re-read live on 2026-11-10: https://nearhackathon.com/HACKATHON.md still answers Q-007 "Testnet for
Intents? None exists or is planned", and the vendor's own docs say the same in two places ("There is no
testnet deployment and no plans for one. We recommend testing on NEAR mainnet using separate dev/test
NEAR accounts"), so the answer is not a stale snapshot. Feature by feature:

- **1Click quotes, deposits and payouts** — mainnet only; the live `/v0/tokens` lists 216 assets whose
`near` entries are all mainnet NEP-141 contracts (the one id containing "test" is a mainnet
sub-account, `test-token.highdome3013.near`, not a test network). This is the integration the track
judges, so Q-010 covers the entry: "Mainnet only where the integration is mainnet-only".
- **Wallet sign-in (NEP-413)** — the standard is network-agnostic, but the wallet's network and the
server's `NEAR_RPC_URL` must agree. Mainnet wallet + testnet RPC fails the access-key read and refuses
the login; testnet wallet + mainnet RPC is the dangerous mix, because the address validator accepts
`alice.testnet`, 1Click would attempt a mainnet delivery to an account that does not exist there, and
the freelancer would not be paid. `lib/ui/config.ts` therefore no longer reads a network variable:
`NEAR_NETWORK` is the literal `"mainnet"`, and the only switch is demo vs real.
- **Storage check and the storage payer (S2.10)** — the check reads the real USDC contract's bounds and
the real account's balance; on testnet it would read a test FT for an account that 1Click will never
pay. Free testnet NEAR (Q-008) buys nothing here, because the spend path is blocked on a funded mainnet
payer and an explicit human yes anyway.
- **Demo mode and dry-run quotes** — already the no-funds paths: `pnpm demo` touches no chain, and a
`dry: true` quote is a real mainnet quote with no deposit address. Testnet is not a substitute for
either, and the e2e suite runs entirely in demo mode.
- **Hosted deployment** — real mode against mainnet; production has no network variable set.
- **Prize payout account** — the submission form's only network requirement is a **mainnet** NEAR
account. That is human-only and unchanged.

### Answered: can the web process and the worker share one PGlite directory? (Phase 8 prep, 2026-11-08)

**No, and the failure is silent.** Measured on `@electric-sql/pglite` 0.2.17 with two separate Node
Expand Down
1 change: 1 addition & 0 deletions ARCHITECTURE_ESSENTIALS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Separate repo from **Stack** (track 01). Never import Stack code; README names S
- **SD-4** Payout assets: USDC on NEAR (default), Base, Arbitrum, Solana, Ethereum; USDT on Ethereum, Solana (ids: ARCHITECTURE §3.2)
- **SD-5** Name: Settle
- **SD-6** Invoice numbering: `INV-0001`, sequential **per user** (`invoices_user_number_uq`), at least 4 digits, grows past 9999 without truncating
- **Mainnet only (S7.14)** NEAR Intents has no testnet and none is planned (vendor docs + hackathon Q-007, re-read 2026-11-10), so `NEAR_NETWORK` in `lib/ui/config.ts` is the literal `"mainnet"`; do not reintroduce a network switch. Demo mode and `dry: true` quotes are the no-funds paths; testnet is used for nothing. The submission's prize-payout account is the one mainnet account the human supplies
- **SD-7** Address checks use `@noble/hashes` (keccak256 → EIP-55, sha256 → base58-check) and `bs58` (Solana, Bitcoin). A chain with no validator is **rejected**, never accepted unchecked. **BTC is validated as a refund-only chain (2026-11-09, S1.7)**: bech32/bech32m and legacy mainnet addresses, never a payout chain

## 🔍 Verify before coding against
Expand Down
4 changes: 4 additions & 0 deletions LAUNCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Read from https://nearhackathon.com/HACKATHON.md on 2026-11-06. What it changes
No rule changed in a way that invalidates work already merged. The two live consequences are:
**the demo video is effectively required**, and **the payload must not gain a `website` field**.

**Re-read live on 2026-11-10 (S7.14):** Q-007 is unchanged, and the vendor's own docs agree —
"There is no testnet deployment and no plans for one." No part of Settle uses testnet; the wallet is
pinned to mainnet and the no-funds paths are demo mode and `dry: true` quotes. See `ARCHITECTURE.md` §11.

---

## 2. Demo video script (S10.1, #81)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ app/ (routes, pages) worker/ (two interval loops)

- **Web app deployed; the worker is not.** The Next.js app is live on Vercel (https://settle-wine-alpha.vercel.app) in **real mode** against a hosted Postgres — landing, NEAR-wallet sign-in, invoice create / list / dashboard / receipt — and `GET /api/health` returns `{"status":"ok","demo":false,"database":"ok"}` from the running deployment, not only from a local boot. It was **re-deployed on 2026-11-09** from the merged tip — the Vercel project is not connected to Git, so a merge does not deploy — and the staleness probe in `DEPLOY.md` §8 went from 404 to 200. Loading the live URL in a real browser then found a hydration mismatch on the landing page (React #418): the server's HTML said wallet sign-in was unavailable while the browser's first render offered it, so React threw the markup away. Fixed here and pinned by the fifth e2e test, then deployed: the live page re-checked in Chromium at 1440 px and 390 px reports the sign-in button enabled, no page or console error, no failed request and no horizontal overflow. A screenshot of that page then caught the one defect no probe could: the hero receipt's amounts inherited the brand field's white text and rendered white-on-white, so the same e2e test now reads the amount's computed colour and fails it, and the fix (a `text-ink` on the card root) was proven by re-injecting the bug and watching the test go red first. A green `/api/health` detects neither problem, which is why the deploy notes now say to probe a route only the new artifact has and then read the first screen's console. It was **re-deployed once more on 2026-11-10** with S1.7: the challenge probe answers 200, `/api/health` is green, the landing page opens in Chromium with no console message, and the live `/api/tokens` carries `refundChain` and lists BTC as refund-only (`settleChain: null`) with no BTC asset among the payouts. The **same day** it was deployed again with S4.15, the dark landing redesign: the served HTML carries the new hero ("Invoice in dollars. Paid in any token."), the challenge probe answers 200, `/api/health` is green, the sign-in button is enabled after hydration, and Chromium at 1440 px and 390 px reports **no page or console error and no horizontal overflow**. Two things that URL does not do yet, stated plainly: **no live payment quote**, because the vendor `ONECLICK_JWT` (S0.8) is not in hand, so the pay page fails closed before it prices anything; and **no background worker**, because a serverless host cannot keep the long-lived 5 s poll / 60 s expire process. That second limit is exactly why `DEPLOY.md` §6 concluded that a two-process host is a paid decision — Render's free-plan page says free plans do not support background workers, and usage-based hosts bill a worker that never idles. A full live payment therefore still needs a host that runs both processes plus the JWT. The offline evidence is unchanged: `pnpm demo`, the E2E browser journey — which drives a **production build** (`pnpm build` + `pnpm start`, the same two commands a host runs) rather than `next dev` — and 671 passing offline tests (672 total, one Postgres-only skip). `DEPLOY.md` also records two constraints that were measured, not assumed: PGlite is single-process — two processes on one directory lost half their writes and killed one outright — so a hosted Settle needs Postgres; and demo mode deliberately refuses an `https://` URL, so the hosted app runs **real mode** (decision `SD-8`) and the demo story lives in `pnpm demo` and the video.
- **A real quote has never been driven offline, and since 2026-11-10 no quote is served without the partner JWT.** The minimum refusal itself is not a guess — `try at least N` was provoked against the live API on 2026-11-09 with unauthenticated _dry_ quotes, which is what fixed the units it is rendered in (S0.13). Then, on **2026-11-10**, the same unauthenticated `POST /v0/quote` — dry or not, on three routes including the USDC→USDC call that had answered 200 the day before — returned `400 Internal server error`, while the same body with a bogus bearer returned `401 Invalid token`. The token list still answers without credentials. So a real payment now needs the partner JWT (S0.8, #11) even for a preview, plus a funded signer, a running worker and a two-process host.
- **No testnet, because NEAR Intents has none.** Re-read live on 2026-11-10: the rules still answer Q-007 "None exists or is planned" and the vendor's docs say "There is no testnet deployment and no plans for one." Every money path is therefore mainnet — the wallet selector is pinned to mainnet (`lib/ui/config.ts`), the storage check reads the real USDC contract, and the no-funds paths are `pnpm demo` and `dry: true` quotes. Testnet NEAR buys nothing here; the submission's prize-payout account is the one mainnet account the human supplies. The full per-path audit is `ARCHITECTURE.md` §11 (S7.14).
- **Refund addresses are checked on five payout chains, plus Bitcoin.** `lib/core/address.ts` validates NEAR, EVM (EIP-55), Solana and, since S1.7, **BTC** — base58-check P2PKH/P2SH and segwit bech32/bech32m, mainnet only. Bitcoin is a _refund-only_ chain: a client can pay from BTC and is refunded there, but Settle never pays out to it. Everything else a client might pay from is still refused with a reason rather than accepted unchecked; for TON and Tron that is a missing validator, and for chains that need a memo it is the missing memo field. The memo list itself is ours and flagged 🔍, because 1Click does not publish which origins require one. Refusing errs safe: an address Settle cannot check is not one it will send money back to.
- **A region block is passed through, not recognised.** The vendor's own wording reaches the client; Settle does not match it against strings it guessed.
- **Rate limits are in-process.** Correct for one instance; N instances would each keep their own bucket. Stated in `ARCHITECTURE.md` §3.1 rather than hidden.
Expand Down
Loading
Loading