Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4633318
Expose the onboarded manifest in the operator console
0xMuang Jul 22, 2026
0fd86fd
Keep the complete local RFQ walkthrough executable
0xMuang Jul 22, 2026
825f2ff
Record the operator manifest snapshot capability
0xMuang Jul 22, 2026
55c5ee0
Keep the interactive RFQ demo reachable after setup
0xMuang Jul 22, 2026
adb5126
Integrate the RFQ trader flow into the local console
0xMuang Jul 22, 2026
de27742
Align RFQ demo amounts with deployed token decimals
0xMuang Jul 22, 2026
3763c27
Add one-click demo readiness checks to the console
0xMuang Jul 22, 2026
325e034
Refresh demo operator nonces for repeated security runs
0xMuang Jul 22, 2026
5469dfe
Make security enforcement demo independently runnable
0xMuang Jul 22, 2026
a7ac798
Make RFQ demo activity visible after settlement
0xMuang Jul 22, 2026
6d76615
Retry demo policy toggles after nonce races
0xMuang Jul 22, 2026
b6acc53
Align dashboard RFQ payloads with backend responses
0xMuang Jul 22, 2026
c6b126e
Complete dashboard endpoint wiring audit
0xMuang Jul 22, 2026
9b6df2f
Restore signed quote wiring across dashboard flows
0xMuang Jul 22, 2026
fd696bf
Expose live RFQ demo events in the operator view
0xMuang Jul 22, 2026
2542df3
Make RFQ console provenance and audit state visible
0xMuang Jul 22, 2026
81702ac
Make the RFQ demo prove real state transitions
0xMuang Jul 22, 2026
a33120e
Show RFQ price context without overstating market data
0xMuang Jul 22, 2026
f4f1867
Make the RFQ demo self-guided and replay-safe
0xMuang Jul 22, 2026
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
85 changes: 85 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Design

## Source of truth
- Status: Active
- Last refreshed: 2026-07-23
- Primary product surfaces: RFQ Trader, Security demo, read-only Operator view
- Evidence reviewed: `services/operator-dashboard/index.html`, `services/operator-dashboard/README.md`, `share/RFQ Trading Console (standalone).html`, RFQ and Operator API contracts

## Brand
- Personality: institutional, precise, calm, compliance-first
- Trust signals: explicit live/fixture labels, exact quote payload review, transaction hashes, block numbers, policy status
- Avoid: consumer-exchange spectacle, unexplained mock data, hidden signing, decorative charts presented as live market data

## Product goals
- Goals: demonstrate quote request → review → compliant settlement without CLI steps; make policy enforcement and operator state visible
- Non-goals: production custody, hosted signing, real Securitize/TA integration, fake multi-maker liquidity
- Success signals: a first-time viewer can complete and explain the demo; every displayed datum has visible provenance

## Personas and jobs
- Primary personas: trader/demo viewer, compliance or product reviewer, protocol operator
- User jobs: request and settle a quote; prove stale signatures cannot bypass current policy; inspect deployment, manifest and confirmed demo events
- Key contexts of use: local Anvil demo, partner presentation, SDK integration review

## Information architecture
- Primary navigation: Trader · RFQ / Security demo / Operator
- Core routes/screens: single dashboard with three role-focused views
- Content hierarchy: environment → action → review → result → audit evidence

## Design principles
- Label provenance: Live, Preview, Demo fixture and Follow-up must never be visually conflated.
- Review before settlement: the exact signed quote is visible before execution.
- Current policy is authoritative: pre-checks are advisory; Router fill-time enforcement is explicit.
- Tradeoff: the MVP uses one live maker and local session history rather than implying a production order book.

## Visual language
- Color: ink `#12253f`, blue `#175ac4`, green `#0a8069`, red `#b7353d`, amber `#c98a2b`, line `#d2dce5`
- Typography: Georgia for display headings; system sans for UI; monospace for addresses, events and payloads
- Spacing/layout rhythm: flat bordered panels, 12–24px internal rhythm, two-column desktop layout
- Shape/radius/elevation: square institutional panels, minimal elevation
- Motion: limited to progress and status changes; no decorative motion
- Imagery/iconography: text and status-first; no unverified logos

## Components
- Existing components to reuse: status blocks, fact rows, quote cards, execution trace, event list, metrics strip
- New/changed components: compliance pre-check, session trade history, live indexed-event summary and log, live firm-rate marker over clearly labeled fixture market context, header help control and in-product presenter guide
- Variants and states: live/preview, available/expired, loading/empty/error/success/rejected
- Token/component ownership: dashboard CSS variables and classes in `services/operator-dashboard/index.html`

## Accessibility
- Target standard: WCAG 2.1 AA for core demo controls
- Keyboard/focus behavior: native buttons, inputs and details controls remain keyboard reachable; the demo guide traps focus, closes with Escape/backdrop/close control and restores focus to the help button
- Contrast/readability: status is conveyed with text in addition to color
- Screen-reader semantics: headings, labels, buttons and native details elements
- Reduced motion and sensory considerations: no essential information depends on animation

## Responsive behavior
- Supported breakpoints/devices: desktop presentation and mobile/tablet below 760px
- Layout adaptations: two columns collapse to one; event rows stack
- Touch/hover differences: controls retain explicit labels and at least practical touch padding

## Interaction states
- Loading: action-specific progress copy and disabled duplicate actions
- Empty: explain which action creates data
- Error: show actionable backend or settlement reason
- Success: show block, transaction and balance delta when available
- Disabled: explain prerequisite through nearby copy
- Offline/slow network: backend health and setup checks expose unavailable services

## Content voice
- Tone: concise, technical and demonstrable
- Terminology: quote, maker, Router, RFQAdapter, manifest, settlement, indexed event
- Microcopy rules: distinguish pre-check from fill-time enforcement; distinguish session state from persisted/indexed state

## Implementation constraints
- Framework/styling system: dependency-free vanilla HTML/CSS/JS served by Node
- Design-token constraints: reuse existing CSS variables; no new frontend dependency for the MVP
- Performance constraints: no blockchain calls or signing in the browser
- Compatibility constraints: current backend returns one live `SignedRFQQuote`; preview makers are non-selectable
- Data-provenance constraint: the live rate is derived from `/demo/quote`; comparison curves, spread, activity and non-live makers remain visibly labeled demo fixtures until market-data and multi-maker APIs exist
- Test/screenshot expectations: smoke and syntax tests are required; visual screenshot comparison is required when a browser runtime is available

## Open questions
- [ ] Replace session-only trade history with a persistent quote/trade lifecycle API.
- [ ] Replace demo event-file bridge with a production RPC ChainReader and finality-aware indexer.
- [ ] Add real multi-maker aggregation only when the backend returns multiple executable quotes.
41 changes: 38 additions & 3 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,9 +375,17 @@ passing
- `scripts/e2e-anvil.sh --mode rfq`는 AMM·lifecycle·surveillance 설명을 건너뛰고
mock TA profile → Toolkit/CLI → backend-signed quote → protected RFQ settlement
→ revoked-maker rejection만 보여주는 짧은 MVP 시연 경로를 제공한다.
- 기존 Operator dashboard는 `Operator view`(read-only snapshot)와 `RFQ demo`
(local quote request/download/CLI settlement handoff) 모드를 제공하며, browser에
private key나 direct transaction endpoint를 추가하지 않는다.
- Operator dashboard는 Trader, Security demo와 read-only Operator view를
제공한다. Trader는 local backend에서 exact signed quote를 요청·검토한 뒤 protected
Router settlement를 실행하고, Security demo는 on-chain maker revoke 상태를
명시적 restore 전까지 유지해 현재 정책 enforcement를 가시화한다. 브라우저에는
private key가 전달되지 않는다.
- Trader의 live firm rate는 `/demo/quote` 금액에서 계산한다. 비교 maker, 가격 곡선,
spread와 활동 통계는 multi-maker/market-data API가 생기기 전까지 명시적으로
`Demo fixture data`와 `Preview only`로 표시해 실제 실행 가능 quote와 구분한다.
- 헤더의 **?** presenter guide가 정상 거래, maker-revocation 보안 시나리오,
live/fixture 경계와 각 버튼의 실제 backend/Operator API 연결을 대시보드 안에서
설명한다.
- backend는 pricing, signing과 nonce 발급만 담당하며 compliance 최종 판단을 하지 않는다.
- production pricing, signer custody, persistent nonce, inventory/risk control과 hosted operation은 명시적으로 범위 밖이다.

Expand Down Expand Up @@ -788,3 +796,30 @@ passing
- 완료 계획: `docs/exec-plans/completed/AMM-001-real-uniswap-v3-e2e.md`
- vendored Solidity source를 제품 `src/`로 복사하지 않는다.
- production fee-tier 승인, LP 운영 정책과 unified deploy CLI는 별도 후속 범위다.

## OPS-003 — Operator Deployment and Manifest Snapshot

### Behavior

- read-only Operator Dashboard가 배포 artifact의 execution/control-plane 주소를 표시한다.
- Demo onboarding 직후 Manifest status, version과 RecipeBinding 수를 snapshot으로 저장한다.
- Operator API가 snapshot을 `/api/v1/manifest`로 제공하고 Dashboard가 이를 표시한다.
- Dashboard, CLI와 RFQ backend가 연결된 local BUIDL-like walkthrough를 한 번에 실행할 수 있다.

### Verification

- `npm test --prefix services/operator-api`
- `npm test --prefix services/operator-dashboard`
- `npm test --prefix services/cli`
- `forge build --offline --jobs 1`
- `scripts/e2e-anvil.sh --profile buidl-like`
- `git diff --check`

### State

passing

### Notes

- snapshot은 demo/reference checkpoint이며 production indexer나 live RPC provider가 아니다.
- production Manifest lifecycle mutation과 governance action은 별도 범위다.
24 changes: 17 additions & 7 deletions PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ source of truth로 사용한다.
bindings, required/path/flag 평가, delayed lifecycle update와 CLI/demo ABI migration)
- `AMM-001 — Canonical Uniswap v3 Pool E2E`(pinned core artifact factory/pool,
CREATE2 preflight, real mint/swap callback와 ERC-3643 protected buy/sell)
- RFQ-first MVP demo refinement(`scripts/e2e-anvil.sh --mode rfq` + existing
Operator dashboard의 `RFQ demo` mode + `docs/rfq-demo-guide.md`)
- RFQ-first MVP demo refinement(`scripts/e2e-anvil.sh --mode rfq` + Trader /
Security / Operator dashboard + `docs/rfq-demo-guide.md`)
- multi-venue 아키텍처와 책임 문서 작성
- Corner Store용 Uniswap v3 최소 배포 profile 분리와 테스트
- ExecutionRouter/VenueRegistry/VenueSelector와 AMM reference adapter skeleton
Expand Down Expand Up @@ -78,6 +78,9 @@ source of truth로 사용한다.
`snapshot`/`restore`, `quote-inspect`(서명자 복구/만료/nonce·승인, 실패 시 exit 1).
reason 디코딩·EIP-712 복구는 기존 lib 재사용. smoke(quote-inspect valid+tampered) +
full live walkthrough로 검증. `forge test --offline` 238/238 유지.
- `OPS-003 — Operator Deployment and Manifest Snapshot`(read-only Dashboard에
execution/control-plane 주소와 onboarding Manifest status/version/RecipeBinding
snapshot 표시, CLI nonce refresh와 전체 BUIDL-like RFQ walkthrough 검증).

## Blocked

Expand All @@ -97,11 +100,18 @@ source of truth로 사용한다.

## Last Session Summary

- RFQ MVP demo는 mock TA-seeded BUIDL-like profile, Toolkit preflight/onboard,
backend EIP-712 quote, protected Router settlement와 revoked-maker rejection을
`--mode rfq` 한 경로로 시연한다. 기존 Operator dashboard는 read-only
Operator view와 quote request/download/CLI handoff용 RFQ demo를 구분하며,
browser private key·direct transaction 권한을 갖지 않는다. `scripts/check.sh`
- 대시보드의 모든 정적·동적 버튼을 endpoint/상태 전이와 대조하고 연결 회귀 검사를
추가했다. 체결된 single-use quote의 재실행을 차단하고 Operator API 오류 처리,
탭 활성 상태와 중복 실행 방지를 보강했으며, 헤더 **?**에서 정상 거래·Security
demo·live/fixture 경계·버튼별 연결을 바로 확인하는 접근 가능한 presenter guide를
제공한다. dashboard smoke와 fresh-port BUIDL-like RFQ E2E(setup, settle,
revoke rejection, state persistence, restore)가 통과했다.
- RFQ MVP dashboard의 준비·상태 확인·quote 요청·검토·Router 체결·maker revoke·
명시적 restore를 실제 local backend와 온체인 상태에 연결했다. revoke는 restore
전까지 유지되고 Operator event index에 settlement와 maker false/true 전이가
기록된다. live quote rate와 indicative comparison chart를 추가하되, 외부 market
feed가 없는 곡선·spread·추가 maker는 fixture/preview로 명확히 구분했다. 브라우저에는
private key가 전달되지 않는다. `scripts/check.sh`
(641/641 Foundry 포함)과 RFQ-only live E2E가 통과했다.
- `AMM-001`에서 vendored pinned Uniswap v3 core artifact로 canonical factory와
pool을 배포하고 CREATE2 주소, 초기화, 실제 liquidity mint/swap callback,
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,12 @@ scripts/e2e-anvil.sh --profile buidl-like --mode rfq
Add `--keep` for an interactive follow-up; the runner restores the demo maker
after its rejection check so a new quote can be filled immediately.

`--keep` leaves both Anvil and the RFQ demo backend running. In another terminal,
request and settle the quote through the protected Router path:
`--keep` leaves both Anvil and the RFQ demo backend running. Open the printed
dashboard URL, select **RFQ demo**, and click **Run compliant RFQ trade**. The
dashboard requests the quote and asks the local backend to settle it through the
protected Router; no CLI copy/paste is required.

For a terminal-only flow, request and settle the quote directly:

```shell
node services/cli/dist/cli/src/index.js rfq-quote \
Expand Down
29 changes: 20 additions & 9 deletions docs/rfq-demo-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ scripts/demo.sh --profile buidl-like

The launcher starts Anvil, deploys the selected profile, starts the RFQ backend,
starts the read-only Operator API and serves the dashboard. Open the printed URL
and press Ctrl-C to stop all local services.
and press Ctrl-C to stop all local services. The same presenter sequence and a
button-to-endpoint map are available from the **?** button in the dashboard
header.

The command exits non-zero on failure. A successful run proves, in order:

Expand All @@ -39,14 +41,23 @@ Then start the existing operator dashboard in a second terminal and open
npm run start --prefix services/operator-dashboard
```

Select **RFQ demo**, click **Check backend**, then click **Run compliant RFQ
trade**. The four visible stages show the mock TA profile, EIP-712 quote,
Router policy decision and on-chain ERC-3643 balance change. Click **Revoke
maker & retry** to show the same flow being rejected. The browser never holds
a private key.

If you prefer the terminal instead of the dashboard, request and settle a new
quote with:
Select **Trader · RFQ** and click **Check & prepare demo**. Then request a firm
quote, select it for review, and execute the selected quote. The four visible
stages show the mock TA profile, EIP-712 quote, Router policy decision and
on-chain ERC-3643 balance change. The price-context panel marks the live firm
rate returned by the backend. Its comparison curves, spread statistics and
additional makers are presentation fixtures and are labeled accordingly; they
are not executable quotes or an external market-data feed.

Open **Security demo**, create a fresh test quote, then click **Revoke maker &
execute**. The maker approval is changed on chain and the stored quote is
rejected at fill time. The maker deliberately stays revoked so the UI and
Operator event log show the real state transition. Click **Restore maker**
before returning to normal trading. The browser never holds a private key.

The dashboard performs the quote request and Router settlement itself; no CLI
copy/paste is needed for the normal demo. If you prefer the terminal instead,
request and settle a new quote with:

```sh
node services/cli/dist/cli/src/index.js \
Expand Down
5 changes: 4 additions & 1 deletion script/DemoConstants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ abstract contract DemoConstants {
// The default live profile is BUIDL-like and enforces a 5M-token minimum.
// Keep enough fixture liquidity for all AMM/RFQ/surveillance scenarios.
uint256 internal constant INVESTOR_QUOTE = 50_000_000 ether;
uint256 internal constant MAKER_RWA = 10_000_000 ether;
// The full runner performs one reference RFQ fill, one dashboard fill and
// one CLI fill; keep enough maker inventory for all three demonstrations.
uint256 internal constant MAKER_RWA = 20_000_000 ether;
uint256 internal constant POOL_RWA = 50_000_000 ether;
uint256 internal constant AMM_TRADE = 5_000_000 ether; // QUOTE in == RWA out (1:1 pool)
uint256 internal constant RFQ_QUOTE_IN = 5_000_000 ether;
uint256 internal constant RFQ_RWA_OUT = 5_000_000 ether;

// Deployment artifact shared between the two scripts.
string internal constant ARTIFACT_PATH = "deployments/anvil-e2e.json";
string internal constant MANIFEST_SNAPSHOT_PATH = "deployments/operator-manifest.json";
}
13 changes: 13 additions & 0 deletions script/DemoScenarios.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,24 @@ contract DemoScenarios is Script, DemoConstants {
&& stored.factsPacked == expected.factsPacked && stored.fullManifestHash == expected.fullManifestHash;
bool ok = stored.status == PolicyStatus.ACTIVE && stored.declaredBy == address(factory)
&& stored.approvedBy == address(factory) && profileOk;
_writeManifestSnapshot(stored, storedBindings);
console2.log(" evidence: ACTIVE selected asset profile, approved by factory");
console2.log(" status(2=ACTIVE) :", uint256(stored.status));
_record(1, ok);
}

function _writeManifestSnapshot(ManifestCore memory manifest, RecipeBinding[] memory bindings) internal {
string memory k = "corner-store-manifest";
vm.serializeAddress(k, "token", address(rwa));
vm.serializeUint(k, "status", uint8(manifest.status));
vm.serializeUint(k, "version", policyReg.manifestVersionOf(address(rwa)));
vm.serializeBytes32(k, "fullManifestHash", manifest.fullManifestHash);
vm.serializeBytes32(k, "historyHash", policyReg.manifestHistoryHashOf(address(rwa)));
vm.serializeUint(k, "recipeBindingCount", bindings.length);
string memory json = vm.serializeUint(k, "supportedEngines", manifest.supportedEngines);
vm.writeJson(json, MANIFEST_SNAPSHOT_PATH);
}

// ---------------------------------------------------------------------
// Scenario 2 — Compliant trade succeeds
// ---------------------------------------------------------------------
Expand Down
6 changes: 4 additions & 2 deletions scripts/demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ done

STATE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/corner-store-demo.XXXXXX")
PID_FILE="$STATE_DIR/pids"
EVENTS_FILE="$STATE_DIR/events.json"
OPERATOR_API_PID=""
DASHBOARD_PID=""

Expand All @@ -57,7 +58,7 @@ cleanup() {
trap cleanup EXIT INT TERM

echo "==> Starting Corner Store local demo"
scripts/e2e-anvil.sh --profile "$PROFILE" --mode "$MODE" \
CORNER_STORE_EVENTS="$EVENTS_FILE" scripts/e2e-anvil.sh --profile "$PROFILE" --mode "$MODE" \
--port "$ANVIL_PORT" --backend-port "$BACKEND_PORT" --pid-file "$PID_FILE" --keep

echo "==> Starting read-only Operator API"
Expand All @@ -68,6 +69,8 @@ if [ "$PROFILE" = "reg-d" ]; then
fi
CORNER_STORE_CONFIG="$CORNER_STORE_CONFIG" \
CORNER_STORE_ARTIFACT="deployments/anvil-e2e.json" \
CORNER_STORE_MANIFEST="deployments/operator-manifest.json" \
CORNER_STORE_EVENTS="$EVENTS_FILE" \
PORT="$OPERATOR_API_PORT" \
node services/operator-api/dist/src/index.js >"$STATE_DIR/operator-api.log" 2>&1 &
OPERATOR_API_PID=$!
Expand Down Expand Up @@ -96,4 +99,3 @@ echo "Demo is ready: http://127.0.0.1:${DASHBOARD_PORT}"
echo "RFQ backend: http://127.0.0.1:${BACKEND_PORT}"
echo "Press Ctrl-C to stop all demo services."
wait "$DASHBOARD_PID"

Loading
Loading