feat(asm-sequencer): settings-UI toggle in both surfaces (wallet committed; Potidaea drafted)
Beta wallet (shells/app/src/screens/SettingsScreen.tsx)
New "ASM sequencer relay" group between Network and Token definitions.
URL input + live reachability probe (useEffect fires on endpoint change,
shows checking → Reachable / Unreachable). Persists via localStorage key
asm-sequencer.endpoint through the sequencerRelay module. Default empty =
trustless tier-4 retry stays in charge.
Server (scripts/asm-sequencer/server.mjs)
Permissive CORS (Access-Control-Allow-Origin: *, methods GET/POST/OPTIONS,
content-type header, 10 min max-age) + explicit OPTIONS preflight handler.
Production deploys tighten this at the reverse proxy; the dev daemon needs
CORS so any wallet/dApp origin can probe /health and POST /claim.
Potidaea (design/potidaea/{app.html, src/main.ts})
Drafted locally but NOT committed — those files carry the DEA asset-side
session's uncommitted network-toggle work on the same lines. My wiring
(wireSequencerSettings + Section 4 render in paintWalletMenu) will rebase
cleanly once that session commits. Browser-verified against the live
chipnet daemon: ✓ reachable chip, saved to LS, menu stays open while
typing, ⚠ unreachable chip for 127.0.0.1:9999.
Snapshot 0280 documents the arc.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
07fd344299
commit
a014f6636f
4 changed files with 168 additions and 4 deletions
|
|
@ -175,13 +175,29 @@ async function readBody(req) {
|
|||
return raw ? JSON.parse(raw) : {};
|
||||
}
|
||||
|
||||
// Permissive CORS for a dev relay — any wallet/dApp origin can probe + claim.
|
||||
// A production deploy behind nginx/caddy can tighten this via the reverse
|
||||
// proxy (Access-Control-Allow-Origin) rather than touching the server.
|
||||
const CORS_HEADERS = {
|
||||
'access-control-allow-origin': '*',
|
||||
'access-control-allow-methods': 'GET, POST, OPTIONS',
|
||||
'access-control-allow-headers': 'content-type',
|
||||
'access-control-max-age': '600',
|
||||
};
|
||||
|
||||
function send(res, status, body) {
|
||||
const data = JSON.stringify(body);
|
||||
res.writeHead(status, { 'content-type': 'application/json', 'content-length': Buffer.byteLength(data) });
|
||||
res.writeHead(status, { 'content-type': 'application/json', 'content-length': Buffer.byteLength(data), ...CORS_HEADERS });
|
||||
res.end(data);
|
||||
}
|
||||
|
||||
const server = createServer(async (req, res) => {
|
||||
// CORS preflight — Chrome fires OPTIONS before any non-simple POST.
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.writeHead(204, CORS_HEADERS);
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (req.method === 'GET' && req.url === '/health') {
|
||||
send(res, 200, { ok: true, ...state.snapshot() });
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { Network, CoreSession } from '../core/wallet';
|
||||
import { TokenImportModal } from '../components/TokenImportModal';
|
||||
import type { TokenTierA } from '@core/token/types.js';
|
||||
|
|
@ -7,6 +7,7 @@ import { BUILD, isNetworkAllowed, FUSE_ENABLED } from '../buildInfo';
|
|||
import type { DevWallet } from '../devWallets';
|
||||
import type { MultiKeyStore, WalletSummary, SeedSummary } from '../keystore/MultiKeyStore';
|
||||
import { ImportFromKeystoreFlow } from './ImportFromKeystoreFlow';
|
||||
import { getSequencerEndpoint, setSequencerEndpoint, sequencerReachable } from '../asm-core/sequencerRelay';
|
||||
|
||||
// Settings — reachable from the topbar gear (not a bottom tab). Security (seed +
|
||||
// PIN/biometric + lock), Privacy (CashFusion toggles), Network (shared with the
|
||||
|
|
@ -68,6 +69,28 @@ export function SettingsScreen({
|
|||
() => (session ? session.registry.listTierA() as TokenTierA[] : []),
|
||||
);
|
||||
|
||||
// ASM sequencer relay — opt-in tier-2 path for same-target reservoir races.
|
||||
// Null endpoint = disabled, which is the default. See
|
||||
// asm-core/sequencerRelay.ts for the probe-first-then-commit dispatch, and
|
||||
// wiki/asm/zero-contention-protocol.md for the trust model.
|
||||
const [seqEndpoint, setSeqEndpoint] = useState<string>(() => getSequencerEndpoint() ?? '');
|
||||
const [seqProbe, setSeqProbe] = useState<'idle' | 'checking' | 'ok' | 'fail'>('idle');
|
||||
const seqEnabled = seqEndpoint.trim().length > 0;
|
||||
useEffect(() => {
|
||||
if (!seqEnabled) { setSeqProbe('idle'); return; }
|
||||
let cancelled = false;
|
||||
setSeqProbe('checking');
|
||||
sequencerReachable(seqEndpoint.trim()).then((ok) => {
|
||||
if (!cancelled) setSeqProbe(ok ? 'ok' : 'fail');
|
||||
});
|
||||
return () => { cancelled = true; };
|
||||
}, [seqEndpoint, seqEnabled]);
|
||||
const commitSeqEndpoint = (next: string) => {
|
||||
const trimmed = next.trim();
|
||||
setSeqEndpoint(trimmed);
|
||||
setSequencerEndpoint(trimmed.length > 0 ? trimmed : null);
|
||||
};
|
||||
|
||||
const handleImported = (token: TokenTierA) => {
|
||||
setRegisteredTokens((prev) => {
|
||||
const next = prev.filter((t) => t.categoryId !== token.categoryId);
|
||||
|
|
@ -199,6 +222,51 @@ export function SettingsScreen({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* ASM sequencer relay — tier-2 low-latency path for same-target reservoir races.
|
||||
Default off (empty endpoint = no relay = tier-4 wallet retry stays in charge).
|
||||
See wiki/asm/zero-contention-protocol.md and snapshot 0279 for the trust model. */}
|
||||
<div className="group">
|
||||
<div className="group-label">ASM sequencer relay</div>
|
||||
<div className="card">
|
||||
<SRow
|
||||
icon="⟶"
|
||||
title="Relay endpoint"
|
||||
sub={
|
||||
seqEnabled
|
||||
? seqProbe === 'checking'
|
||||
? 'Checking reachability…'
|
||||
: seqProbe === 'ok'
|
||||
? 'Reachable — ASM claims will try the relay first, local retry if it fails'
|
||||
: seqProbe === 'fail'
|
||||
? 'Unreachable right now — ASM claims will use local retry'
|
||||
: 'Endpoint set — not yet probed'
|
||||
: 'Not set — ASM claims use the local client-side retry (tier-4)'
|
||||
}
|
||||
right={
|
||||
<input
|
||||
type="url"
|
||||
inputMode="url"
|
||||
placeholder="https://sequencer.example"
|
||||
value={seqEndpoint}
|
||||
onChange={(e) => setSeqEndpoint(e.currentTarget.value)}
|
||||
onBlur={(e) => commitSeqEndpoint(e.currentTarget.value)}
|
||||
aria-label="Sequencer relay endpoint URL"
|
||||
style={{
|
||||
width: 180, padding: '4px 8px', fontSize: 12,
|
||||
border: '1px solid rgba(255,255,255,0.12)', borderRadius: 4,
|
||||
background: 'transparent', color: 'inherit',
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="empty" style={{ marginTop: 9 }}>
|
||||
Opt-in. The relay orders claims into one reservoir chain for lower latency; it never holds
|
||||
your keys and the covenant enforces the swap math either way. Leave empty to keep the
|
||||
trustless retry path.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Token Definitions — persistent registry */}
|
||||
<div className="group">
|
||||
<div className="group-label">Token definitions</div>
|
||||
|
|
|
|||
78
snapshots/0280-asm-sequencer-settings-ui-toggle.md
Normal file
78
snapshots/0280-asm-sequencer-settings-ui-toggle.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
domain: asm
|
||||
summary: "Settings-UI toggle for the ASM sequencer relay in both surfaces. Beta wallet gets a new 'ASM sequencer relay' group in SettingsScreen with URL input + live reachability probe. Potidaea's dynamic walletMenu gains the same input + status chip (drafted, not yet committed — needs the DEA session's co-mingled main.ts/app.html changes to land first). Server gained permissive CORS so browser probes succeed. Browser-verified reachable↔unreachable transitions against a live chipnet daemon."
|
||||
tags: asm, sequencer, tier-2, zero-contention, settings-ui, wallet-wire, potidaea, cors
|
||||
---
|
||||
|
||||
# Snapshot 0280 — ASM sequencer relay settings-UI toggle
|
||||
|
||||
**Date:** 2026-10-02
|
||||
**Track:** shells/app/src/screens/SettingsScreen.tsx · design/potidaea/{app.html, src/main.ts} (local only) · scripts/asm-sequencer/server.mjs
|
||||
**Status:** ✅ beta wallet committed + pushed · ⏳ Potidaea wiring drafted locally, blocked on co-mingled DEA-session commit · ✅ server CORS committed · ✅ browser-verified
|
||||
|
||||
Follow-up to [0279](0279-asm-sequencer-full-stack-userfunded-wallet-wire-systemd.md). Exposes `sequencerRelay.ts`'s `getSequencerEndpoint` / `setSequencerEndpoint` through a user-facing control in each surface, plus a live `/health` reachability probe.
|
||||
|
||||
## What ships in this commit
|
||||
|
||||
### Beta wallet — `shells/app/src/screens/SettingsScreen.tsx`
|
||||
|
||||
New group between "Network" and "Token definitions":
|
||||
|
||||
```
|
||||
ASM sequencer relay
|
||||
┌────────────────────────────────────────────────────┐
|
||||
│ ⟶ Relay endpoint [ https://sequencer.example ] │
|
||||
│ Not set — ASM claims use the local client-side │
|
||||
│ retry (tier-4) │
|
||||
└────────────────────────────────────────────────────┘
|
||||
Opt-in. The relay orders claims into one reservoir chain for
|
||||
lower latency; it never holds your keys and the covenant
|
||||
enforces the swap math either way. Leave empty to keep the
|
||||
trustless retry path.
|
||||
```
|
||||
|
||||
Live `useEffect` probe fires on every endpoint change: `checking…` → `Reachable — ASM claims will try the relay first, local retry if it fails` on a 200 `/health`, or `Unreachable right now — ASM claims will use local retry` on failure. tsc clean on all my files (pre-existing errors in `ExchangePanel.tsx` / `SwapPanel.tsx` / `UniformFiatScreen.tsx` are untouched).
|
||||
|
||||
### Server — `scripts/asm-sequencer/server.mjs`
|
||||
|
||||
Added permissive CORS headers (`Access-Control-Allow-Origin: *`, methods `GET, POST, OPTIONS`, headers `content-type`, 10 min max-age) + `OPTIONS` preflight handler. A production deploy behind nginx tightens this at the proxy layer; the dev daemon needs it so browser fetches from any wallet/dApp origin succeed.
|
||||
|
||||
### Potidaea — DRAFTED, uncommitted
|
||||
|
||||
The dApp's `walletMenu` is **dynamically rebuilt** by `paintWalletMenu` in `design/potidaea/src/main.ts` each time it opens (there's no static HTML to attach the input to). My wiring injects Section 4 — "ASM relay" — into the renderer's `items` array and attaches `wireSequencerSettings()` after each repaint. `wireSequencerSettings()` loads the saved endpoint, binds blur/change commit handlers, live-probes reachability, and stops click-propagation so typing inside the input doesn't trigger the mockup's document-level `closeAll`.
|
||||
|
||||
The TS compiles and the dApp builds. **Not committed** because `main.ts` and `app.html` carry the DEA asset-side session's in-flight network-toggle work on the same lines; staging them would commit someone else's uncommitted work. When the DEA session lands its commit, my Potidaea wiring rebases cleanly on top (my hunks are additive and don't overlap theirs).
|
||||
|
||||
## Browser verification
|
||||
|
||||
Spawned the daemon on 127.0.0.1:8710 (chipnet, COORD=h, TOKEN=asm2), reloaded Potidaea dev-server at localhost:5185, opened walletMenu, pasted `http://127.0.0.1:8710` into the input:
|
||||
|
||||
- `Access-Control-Allow-Origin: *` header present in `/health` response.
|
||||
- Status chip transitioned from `off` → `checking…` → `✓ reachable` (ok class).
|
||||
- `localStorage['asm-sequencer.endpoint']` persisted the URL.
|
||||
- Menu stayed open while typing (click-propagation stop confirmed).
|
||||
- Entering an unreachable URL (`127.0.0.1:9999`) produced `⚠ unreachable` (warn class).
|
||||
|
||||
## Why Potidaea needs the dynamic injection
|
||||
|
||||
The walletMenu `hdrmenu` in `app.html` is a stub that `paintWalletMenu` fully replaces on every open with per-wallet rows (`Wallet 1 ✎ ⧉ ✕`, Attach-another, Session). Any static HTML in the stub gets wiped. The settings sub-block has to live in the renderer, not the HTML. This is a change in approach from my first draft (which added static HTML) and is already encoded in the local main.ts work.
|
||||
|
||||
## Trust posture reminder
|
||||
|
||||
Nothing about this toggle changes the trust model from [0279](0279-asm-sequencer-full-stack-userfunded-wallet-wire-systemd.md): default disabled (empty endpoint = trustless tier-4 retry), opt-in only, the covenant enforces swap math regardless of relay path. Users keep their keys locally in both the coord-funded `/claim` and the user-funded `/tip` + `/submit` flows.
|
||||
|
||||
## Files committed in this snapshot
|
||||
|
||||
- [`scripts/asm-sequencer/server.mjs`](../scripts/asm-sequencer/server.mjs) — permissive CORS + OPTIONS preflight
|
||||
- [`shells/app/src/screens/SettingsScreen.tsx`](../shells/app/src/screens/SettingsScreen.tsx) — new "ASM sequencer relay" group with live probe
|
||||
|
||||
## Files drafted but not committed (co-mingled with DEA session)
|
||||
|
||||
- `design/potidaea/src/main.ts` — adds `wireSequencerSettings` + Section 4 renderer in `paintWalletMenu` + import of `sequencerRelay` helpers
|
||||
- `design/potidaea/app.html` — no net change (my earlier static block was removed in favor of the dynamic render)
|
||||
|
||||
## Cross-references
|
||||
|
||||
- [0272](0272-wallet-asmcore-optimistic-chain-retry.md), [0275](0275-asm-forced-race-retry-proof-chipnet.md), [0277](0277-potidaea-orbital-swap-retry-adaptation.md) — tier-4 retry wire + proofs
|
||||
- [0278](0278-asm-sequencer-service-drafted-and-proved.md), [0279](0279-asm-sequencer-full-stack-userfunded-wallet-wire-systemd.md) — tier-2 sequencer daemon + chipnet proofs
|
||||
- `wiki/asm/zero-contention-protocol.md` — handoff doc
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
> Duplicate snapshot numbers exist (0018, 0019, 0022, 0027, 0053, 0054, 0057, 0062, 0083, 0084,
|
||||
> 0144, 0145, 0153, 0164) — they are distinct files, disambiguated below by slug.
|
||||
|
||||
_322 snapshots · 322 tagged · 8 domains · regenerate after adding one._
|
||||
_323 snapshots · 323 tagged · 8 domains · regenerate after adding one._
|
||||
|
||||
## Quick-find — all snapshots (Ctrl-F by №, domain, tag, or word)
|
||||
|
||||
|
|
@ -338,6 +338,7 @@ _322 snapshots · 322 tagged · 8 domains · regenerate after adding one._
|
|||
| [0277](0277-potidaea-orbital-swap-retry-adaptation.md) | asm | asm potidaea orbital-swap retry zero-contention chipnet wallet-parity | Potidaea dApp (navigate.st/bns/potidaea.asm) adopts the tier-4 client-side optimistic chain + retry pattern shipped in the beta wallet AsmCore (snapshot 0272): claimViaWc / claimViaLocalSigner / claimViaLocalSignerShare wrapped with silent re-broadcast on txn-mempool-conflict, retry-status banner in pendingSheet, resolved-via-N badge on doneSheet. tsc clean, dApp built. |
|
||||
| [0278](0278-asm-sequencer-service-drafted-and-proved.md) | asm | asm potidaea orbital-swap sequencer tier-2 zero-contention chipnet proof daemon relay | Tier-2 ASM sequencer service drafted as a coordinator-funded HTTP relay + tested end-to-end on chipnet. 5 simultaneous /claim requests → 5/5 accepted with the daemon-assigned order forming a single reservoir chain (each tx spent the previous tx's reservoir output). Complements the tier-4 wallet retry from 0272/0275/0277 by adding the low-latency relay path with the wallet retry as fallback. |
|
||||
| [0279](0279-asm-sequencer-full-stack-userfunded-wallet-wire-systemd.md) | asm | asm sequencer tier-2 zero-contention chipnet systemd user-funded wallet-wire potidaea proof | Three-part completion of the tier-2 sequencer arc: (1) systemd unit + deploy README for running the daemon as a long-lived service; (2) user-funded /tip + /submit endpoints that remove the 'relay holds funds' trust step, chipnet-proved 5/5 (users signed their own BCH inputs, mean 3 attempts via 409-stale retry); (3) wallet-side sequencerRelay.ts client in both shells/app and design/potidaea with probe-first-then-commit race-free dispatch. Plus a chipnet-fund-from-h.mjs helper that topped up A/C/E/F/G from wallet H. |
|
||||
| [0280](0280-asm-sequencer-settings-ui-toggle.md) | asm | asm sequencer tier-2 zero-contention settings-ui wallet-wire potidaea cors | Settings-UI toggle for the ASM sequencer relay in both surfaces. Beta wallet gets a new 'ASM sequencer relay' group in SettingsScreen with URL input + live reachability probe. Potidaea's dynamic walletMenu gains the same input + status chip (drafted, not yet committed — needs the DEA session's co-mingled main.ts/app.html changes to land first). Server gained permissive CORS so browser probes succeed. Browser-verified reachable↔unreachable transitions against a live chipnet daemon. |
|
||||
|
||||
## Wallet UI (shells/app) `(103)`
|
||||
|
||||
|
|
@ -445,7 +446,7 @@ _322 snapshots · 322 tagged · 8 domains · regenerate after adding one._
|
|||
- [0272-wallet-asmcore-optimistic-chain-retry](0272-wallet-asmcore-optimistic-chain-retry.md) — AsmCore beta wires the tier-4 client-side optimistic chain + retry pattern — swap/mint/swap-all now silently re-plan against the mempool-inclusive reservoir tip and re-broadcast on `txn-mempool-conflict`, resolving the same-target reservoir race client-side (chipnet-measured 1/6 → N/N on the naïve path) · _wallet, asm, orbital-swap, potidaea, agora, chipnet, retry, zero-contention_
|
||||
- [0276-potidaea-chart-tab-plan](0276-potidaea-chart-tab-plan.md) — Design for a Potidaea Chart tab — historical price chart of any asset in USD, powered by a lean off-chain oracle history + on-chain covenant rate for MBAs · _potidaea, ui, chart, oracle, price-history, plan_
|
||||
|
||||
## ASM / Orbital Swap / Potidaea / Anthemus `(44)`
|
||||
## ASM / Orbital Swap / Potidaea / Anthemus `(45)`
|
||||
|
||||
- [0002-swap-core](0002-swap-core.md) — swap core landed · _swap_
|
||||
- [0005-q4-handoff](0005-q4-handoff.md) — Q4 answer + chipnet validation plan, pre-switch handoff
|
||||
|
|
@ -491,6 +492,7 @@ _322 snapshots · 322 tagged · 8 domains · regenerate after adding one._
|
|||
- [0277-potidaea-orbital-swap-retry-adaptation](0277-potidaea-orbital-swap-retry-adaptation.md) — Potidaea dApp (navigate.st/bns/potidaea.asm) adopts the tier-4 client-side optimistic chain + retry pattern shipped in the beta wallet AsmCore (snapshot 0272): claimViaWc / claimViaLocalSigner / claimViaLocalSignerShare wrapped with silent re-broadcast on txn-mempool-conflict, retry-status banner in pendingSheet, resolved-via-N badge on doneSheet. tsc clean, dApp built. · _asm, potidaea, orbital-swap, retry, zero-contention, chipnet, wallet-parity_
|
||||
- [0278-asm-sequencer-service-drafted-and-proved](0278-asm-sequencer-service-drafted-and-proved.md) — Tier-2 ASM sequencer service drafted as a coordinator-funded HTTP relay + tested end-to-end on chipnet. 5 simultaneous /claim requests → 5/5 accepted with the daemon-assigned order forming a single reservoir chain (each tx spent the previous tx's reservoir output). Complements the tier-4 wallet retry from 0272/0275/0277 by adding the low-latency relay path with the wallet retry as fallback. · _asm, potidaea, orbital-swap, sequencer, tier-2, zero-contention, chipnet, proof, daemon, relay_
|
||||
- [0279-asm-sequencer-full-stack-userfunded-wallet-wire-systemd](0279-asm-sequencer-full-stack-userfunded-wallet-wire-systemd.md) — Three-part completion of the tier-2 sequencer arc: (1) systemd unit + deploy README for running the daemon as a long-lived service; (2) user-funded /tip + /submit endpoints that remove the 'relay holds funds' trust step, chipnet-proved 5/5 (users signed their own BCH inputs, mean 3 attempts via 409-stale retry); (3) wallet-side sequencerRelay.ts client in both shells/app and design/potidaea with probe-first-then-commit race-free dispatch. Plus a chipnet-fund-from-h.mjs helper that topped up A/C/E/F/G from wallet H. · _asm, sequencer, tier-2, zero-contention, chipnet, systemd, user-funded, wallet-wire, potidaea, proof_
|
||||
- [0280-asm-sequencer-settings-ui-toggle](0280-asm-sequencer-settings-ui-toggle.md) — Settings-UI toggle for the ASM sequencer relay in both surfaces. Beta wallet gets a new 'ASM sequencer relay' group in SettingsScreen with URL input + live reachability probe. Potidaea's dynamic walletMenu gains the same input + status chip (drafted, not yet committed — needs the DEA session's co-mingled main.ts/app.html changes to land first). Server gained permissive CORS so browser probes succeed. Browser-verified reachable↔unreachable transitions against a live chipnet daemon. · _asm, sequencer, tier-2, zero-contention, settings-ui, wallet-wire, potidaea, cors_
|
||||
|
||||
## FIATm / BCHm / MBA (backed currency) `(58)`
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue