Per-feature design docs for the Verex prediction market, in the Category → Feature → to-do
structure. The full design document & roadmap is appended below (folded in from the former
plan/ folder); this top section is the per-feature index.
Status is keyed to the 10-step roadmap (§1.4 in the design document below):
S1 ✅ · S2 ✅ · S3 ✅* · S4 ✅ · S6 partial* · S9 partial* · S5, S7–S8, S10 planned — the
detailed per-step audit (2026-08-03, all 10 steps re-audited 2026-08-18, spot-checked again
on the 08-21 plan reset) lives in
docs/tasks/current-plan.md → Roadmap status; that table is
authoritative for step-level status, and the unchecked §1.4 checkboxes below predate it.
Plan reset 2026-08-21 (jay): the 2026-08-03 batch plan shipped waves 0–2 and was archived at
docs/tasks/aug-03-plan.md; its unfinished tail and everything it
deferred now live in Backlog below.
Update 2026-09-04: W6 — a counterparty verex does not custody — is built and proven
(merged 2026-08-26, exercised unattended on 2026-09-02 by rabbit’s J2 agent trading through it);
status and the one open sub-item (W6.5, match-time funds re-check) live in
docs/tasks/current-plan.md → W6. Local dev now runs on an
anvil fork of Sepolia (one root .env, 7702-aware seed).
| Category | Roadmap | Doc | Status |
|---|---|---|---|
| Markets | S2 | markets.md | ✅ Done — oracle-typed markets live on Sepolia (staging + prod) and the local fork; create → trade → resolve works |
| Negative-risk (multi-outcome) | post-S2 | negative-risk-markets.md | ⬜ Design only — no NegRisk adapter under packages/contracts/src |
| Market groups & probability sums | post-S2 (design) | market-groups.md — when outcome YES prices must sum to 100% and when they must not (exclusive · directional/nested · independent); normalization + invariant rules per group type | ⬜ Design only — no groupType in schema.prisma, seeded groups mis-modelled (V5.1) |
| Trading & orders | S2 | trading-orders.md | ✅ Done — CLOB matching against the LMSR operator; external signed makers since 2026-08-26 (W6), funds read-and-reject; open: W6.5 match-time re-check |
| Settlement & redeem | S2 | settlement-redeem.md | ✅ Done — settle worker + external redeem recorded from the verified receipt (W6.4); external redeem costs the holder gas, trading does not |
| Oracle (resolution) | S2 → S6 | oracle.md | ◐ Partial — mock path proven end-to-end; the live UMA adapter is deployed but has never resolved a market (V1.2, A5 open → W1) |
| MM Agent | S2.5 → S6 | mm-agent.md | ✅ Done, differently — in-process mm.ts LMSR ladder, not a separate worker (structural drift noted in the plan) |
| Hybrid AMM + CLOB | early (priority) | hybrid-amm-clob.md — incl. Extreme-probability handling (CPMM tail slippage → simulation · curve decision · tail guard, 2026-07-17) | ◐ Partial — LMSR quoting lives inside the CLOB today; the on-chain pool (phase B) deferred to mainnet (V3.1) |
| Account abstraction | S7–S8 | account-abstraction.md | ⬜ Not started (V4) — the fork seed’s 7702 hygiene is not AA |
| API & indexer | S4–S5 | api-indexer.md | ◐ Split — API ✅ (Fastify + Cloud SQL, staging + prod); indexer dropped by decision, read-only checker queued as W5 (V3.2) |
| Web UI | S3 | web-ui.md | ✅ Done — Polymarket-style feed + market pages on Cloud Run |
| MCP interface | S3 → S8 | mcp-interface.md | ⬜ Not built — packages/mcp-server does not exist; queued as W7 |
| Onboarding & payments | S8–S9 | onboarding-payments.md | ⬜ Not started (V4) |
| Runtime validation (Zod) | incremental — CLI now · api S4 · mm-agent S2.5 | zod-validation.md — env/ABI/JSON boundary validation + inferred types; folds in audit item A2 | ⬜ Not started — no zod imports under packages/*/src |
| Markets as tokens | post-S2 (exploratory) | markets-as-tokens.md — ERC-20 wrapper for CTF outcome shares → external DeFi composability (DEX listing, lending, bots) | ⬜ Exploratory design only |
| CCIP market results | S6-adjacent (exploratory) | ccip-market-result.md — Chainlink CCIP MarketResultReceiver + CCIPLocalSimulator local test setup (Foundry/Hardhat); cross-chain resolution path for the oracle Stage-2 track |
⬜ Exploratory design only |
| Thirdweb | exploratory | thirdweb.md — platform bundle vs hand-rolled parts (Connect wallets/AA · Engine backend tx · browser-signing deploy); check item: review the Rabbit-side Thirdweb feature too before deciding | ⬜ Exploratory — decision not made |
| Observability | S4-adjacent (exploratory) | observability.md — OpenTelemetry-first instrumentation with a swappable export target (Cloud Trace now, Datadog later); ChainJob worker traced first since metrics structurally can’t answer “which step is slow”, plus a standing metric-cardinality rule | ⬜ Design only (V5.2) |
Hierarchy: Category (file) → Feature (bold item) → to-do (checkbox); (you) = needs your decision or action.
Status column added 2026-09-04 — audited against
packages/*/src,schema.prismaand the plan’s roadmap table, not against doc text. Legend: ✅ done · ◐ partial · ⬜ not started/design only.
plan/)Why this section exists (2026-08-21, jay). The batch plan (aug-03-plan.md) delivered waves 0–2 and closed all five gates, so it was archived and current-plan.md restarted empty. What it did not deliver, and what it consciously deferred, is listed here rather than left implied by a retired plan. Nothing was deleted — the reasoning for each deferral stays verbatim in the archive, and this is the status surface. Verified against
mainon 2026-08-21 (packages/*/src,packages/contracts/src,.github/workflows/,schema.prisma), not against the commit log.
Wave 2 shipped the code and the deploy: UmaCtfAdapter.sol exists, staging’s
deployments.json carries umaAdapter 0x1B45F820… pointed at UMA’s real Sepolia
OptimisticOracleV2 0x9f1263B8…, oracleType is a first-class Market field fixed at creation,
/create offers the choice, the market page shows the badge, resolve.ts branches on it, and
uma-demo.ts + ../runbooks/uma-adapter.md walk
propose → dispute → vote → finalize. What was never run is wave 3.
| Item | Status | Gap | |
|---|---|---|---|
| V1.1 | Fresh seed on staging | ⬜ not run | wave 2 changed the backbone (oracle-typed markets), so staging wants a first-run seed — no SKIP_SEED |
| V1.2 | ≥1 market resolved end-to-end through the live adapter, winner redeems | ⬜ not verified | this is the §1.4 milestone and what closes audit item A5 (operator-SPOF). The demo path is proven against the mock oracle (MockOptimisticOracleV2.sol); live Sepolia is untested |
| V1.3 | The CD workflow performing that deploy itself | ⬜ not verified | .github/workflows/deploy-staging.yml is on main and workflow_dispatch-able, but no run has been confirmed |
Until V1.2 passes, S6 stays ◐ partial and A5 stays open — the adapter being deployed is not the same claim as the adapter having resolved anything.
ci.yml, the half of task 2 that was never written ⬜ The batch plan specified two workflows. Only the CD half exists. The CI half — pnpm install
(corepack-pinned), turbo tsc/build for sdk/api/web, forge test in packages/contracts,
prisma validate, pnpm-store cache, no deploy credentials — was never built, so nothing
type-checks a PR automatically today. Done when: a PR with a deliberate type error goes red and
a clean PR goes green including forge tests.
These were not forgotten; each was ruled out with a reason worth not re-deriving. Full argument in the archive.
| Item | Why it was deferred | When to revisit | |
|---|---|---|---|
| V3.1 | LMSR phase B — on-chain pool + smart routing + slo-mo fallback | G1 closed NO (jay, 2026-08-04): every benefit is a benefit of not trusting the operator, and on Sepolia with test USDC there is no adversary and nobody who can lose money | mainnet |
| V3.2 | S5 indexer | dropped 2026-08-03 — the justification did not survive reading the code; SETTLE_MATCH is already idempotent and onFailed compensates. Reframed as an observability tool, not a correctness one; a read-only DB-vs-chain consistency checker gets most of the value for none of the subsystem. Second trigger, 2026-08-25: the drop rested on “the DB is written only by the API”, and W6 ends that — an external holder can redeem, split or merge on CTF directly, and can move funds out from under a resting order. Still not a subsystem: the reframed read-only checker is the right size, and the first thing it should check is the resting-order gap in W6 |
after V1 — the adapter adds on-chain state the DB mirrors, including disputes that can change an answer days later — or once external makers are live. That trigger fired 2026-08-26: W6 is live, so the read-only checker is now actionable (queued as W5 in the plan) |
| V3.3 | ChainlinkOracleAdapter |
demoted to optional 2026-08-03 by counting the seed: 1 of 13 markets is Chainlink-answerable, 13 of 13 suit UMA’s YES_OR_NO_QUERY. A strict subset of what UMA already covers |
only to tick the “≥1 market per adapter” milestone, using eth-above-10k-2026 |
| V3.4 | The constrained admin override inside the UMA adapter | pure UMA is the more principled default for a Sepolia demo; the override matters if mainnet is ever the goal. Note it does not fully close A5 — it makes the operator’s lever exceptional, constrained, and visible on-chain instead of the only path | mainnet |
One open question that survives from wave 2 and is not written down anywhere else: who pays
adapter gas, and who funds the bond. The bond currency is settled — Sepolia WETH
0x7b79995e…98E7f9, chosen for self-service (we wrap it ourselves) over UMA’s zero-final-fee
USDC, which we cannot mint. Bond size (0.01 WETH) is an arbitrary demo knob.
Re-confirmed 2026-08-21 against packages/*/src. These are roadmap items, not owed work; they
are here so a cold session does not have to re-grep to learn they are empty.
| Step | Status | Confirmed by |
|---|---|---|
| S5 Indexer | ⬜ none | no packages/api/src/indexer.ts; the DB is written only by the API — see V3.2 |
| S7–S8 AA / cross-chain | ⬜ none | no 4337 / session-key references under packages/*/src; no CCIP or LayerZero either. (2026-09-04 nuance: the fork seed is now 7702-aware — it probes and strips dead 7702 delegations on reused test accounts — but that is account hygiene, not an AA feature.) Design in account-abstraction.md, ccip-market-result.md |
| S8–S9 Stripe onboarding | ⬜ none | no stripe references under packages/*/src. Design in onboarding-payments.md |
| S10 Final | ⬜ none | — |
| S3 gaps | ⬜ 2 open | packages/mcp-server does not exist (mcp-interface.md); ADR 0001 was never written (docs/architecture/ holds only the singleton-vs-factory ADR) |
| Item | State | |
|---|---|---|
| V5.1 | Market group types + probability-sum invariants (market-groups.md, designed 2026-08-21) | ⬜ design only — MarketGroup exists in schema.prisma but there is no groupType field, so exclusive / directional-nested / independent groups are not yet distinguishable and the normalization rules have nothing to key off |
| V5.2 | Observability — OTel-first, swappable backend (observability.md, designed 2026-08-17) | ⬜ design only — no OpenTelemetry references under packages/*/src. The doc’s own sequencing puts the ChainJob worker first, since metrics structurally cannot answer “which step is slow” |
“사용자는 단순히 질문에 베팅하고, 시스템은 자동으로 결과를 정산한다.”
Verex는 다음을 목표로 하는 Web3 애플리케이션이다:
사용자는 질문에 베팅만 하면 되고, 결과 정산·유동성·결제 경험은 시스템이 자동화한다.
포함
제외 (초기 단계)
planning 브랜치 history로만 보존 — 메인 백본은 S2부터 Polymarket CTF Exchange (CLOB) (§4.5 transition note 참고)§4의 phase 단위 로드맵을 step 단위로 분해한 일정. 각 step은 핵심 산출물 + 마일스톤 둘을 가진다 (예상 시간 열은 2026-08-18 제거 — jay). 일정이 밀리면 다음 step으로 미루지 말고 범위를 줄인다 (원칙 §9.1).
| Phase · Step | 핵심 산출물 | 마일스톤 |
|---|---|---|
| Phase 1 — Scaffold · S1 ✅ | - [x] Market / MarketFactory parimutuel scaffold (학습 패스)- [x] SDK 모양 (factory + market client 패턴, ABI sync) - [x] CLI + commander demo - [x] forge-std + foundry tooling |
- [x] M1: forge test 17/17 - [x] M2: anvil 위 end-to-end CLI demo |
| Phase 1 — Core (CTF v2) · S2 | - [ ] Gnosis CTF 분석 (~2일) — IConditionalTokens 인터페이스 + 5 핵심 함수 (prepareCondition / splitPosition / mergePositions / redeemPositions / reportPayouts) + position ID 수학 + Polymarket Exchange가 CTF를 어떻게 호출하는지 → reading note docs/analysis/gnosis-ctf-research.md- [ ] Polymarket CTF Exchange import + Gnosis CTF (ERC-1155) 통합 - [ ] USDC mock collateral (anvil) - [ ] Manual oracle (Stage 1 of 3) — operator EOA가 prepareCondition(ourEOA, ...) + reportPayouts(...) 직접 호출. Chainlink/UMA 도입 전까지 모든 마켓의 resolve 경로 (§2.2.7)- [ ] SDK 표면 전환 — buyYes/buyNo → fillOrder/fillOrders + signOrder (EIP-712)- [ ] MM Agent v0 (paper-trading) — CLOB가 동작할 최소 maker - [ ] CLI을 order-based flow로 갱신 |
- [ ] CTF mint → split → merge → redeem 한 사이클이 Foundry 테스트로 통과 - [ ] CTF order fill end-to-end on anvil - [ ] MM v0가 양방향 quote 유지 - [ ] Manual operator가 마켓을 resolve해서 winner가 redeem |
| Phase 1 — Web MVP · S3 | - [ ] Web /markets Polymarket-style feed (실 CTF 데이터)- [ ] /markets/[addr] order book + buy UI- [ ] packages/mcp-server 스캐폴딩 + 2 read tool 구현 (list_markets, get_market)- [ ] ADR 0001-mcp-server-as-canonical-agent-interface.md |
- [ ] Metamask: order 서명 → fill → position 표시 - [ ] 두 지갑 시연 영상 |
| Phase 2 — Infra+Data · S4 | - [ ] packages/api Fastify (/markets, /orders, /positions/:user)- [ ] Postgres 스키마 (Markets/Orders/Fills/Positions) - [ ] 로컬 docker-compose |
- [ ] API smoke 테스트 통과 |
| Phase 2 — Infra+Data · S5 | - [ ] Indexer (OrderFilled, PositionsMerged, PayoutRedemption → Postgres)- [ ] Pub/Sub 로컬 에뮬레이터 - [ ] genesis 백필 |
- [ ] 체인 ↔ DB 동기화 검증 |
| Phase 2 — Infra+Data · S6 | - [ ] Chainlink adapter (Stage 2 of 3) — ChainlinkOracleAdapter.sol 컨트랙트가 Chainlink price feed 읽고 endTime 후 reportPayouts 자동 호출. 숫자 기반 마켓 (“ETH > $4000 by date X”) 용 (§2.2.7)- [ ] UMA adapter (Stage 3 of 3) — UMAOptimisticOracleAdapter.sol 컨트랙트가 UMA OptimisticOracleV2.requestPrice 통합. 이벤트/뉴스 마켓 (“Did Brazil win?”) 용 — Chainlink가 답할 수 없는 주관적 질문 (§2.2.7)- [ ] MM Agent v1 (실거래 + 리스크 한도 + 서킷 브레이커) |
- [ ] 적어도 한 마켓을 Chainlink adapter로 resolve - [ ] 적어도 한 마켓을 UMA adapter로 resolve - [ ] MM v1 paper → live 전환 체크리스트 통과 |
| Phase 3 — Advanced · S7 | - [ ] AA 전략 결정 — ERC-4337 / EIP-7702 / hybrid (§11.4 B2) → ADR 0002-aa-strategy.md- [ ] AA wallet 구현 + Web AA 통합 - [ ] session key 권한 모델 확정 (§11.1 미결 1번) - [ ] One-click betting (production) — approve(USDC) + fillOrder 1 서명 (§11.4 B3)- [ ] Auto-claim delegate 컨트랙트 + scheduler (§11.4 B6) — 사용자 EOA에 대해 ONLY redeemPositions 허용하는 최소 delegate; backend scheduler가 resolved 마켓 watch하고 자동 트리거 |
- [ ] 사용자가 AA wallet으로 베팅 - [ ] 1 서명으로 approve+fill 동작 - [ ] resolved 마켓의 winner가 수동 호출 없이 USDC 수령 |
| Phase 3 — Advanced · S8 | - [ ] CCIP/LayerZero 크로스체인 참여 - [ ] MCP write-path tool 활성화 ( buy_yes/no, claim — session key 경유)- [ ] Gasless onboarding (production) (§11.4 B4) — Paymaster가 신규 지갑의 첫 N=5 거래 후원 - [ ] Paymaster spend tracker (§11.4 B7) — per-wallet 카운터 (off-chain DB 또는 on-chain mapping; S8 시작 시 결정) |
- [ ] 다른 체인에서 베팅 - [ ] MCP로 베팅 시연 - [ ] 신규 유저가 ETH 0으로 베팅 완주 - [ ] N+1번째 거래에서 후원 중단 동작 확인 |
| Phase 3 — Advanced · S9 | - [ ] Stripe checkout → backend → mock USDC 지급 - [ ] GCP Cloud Run 배포 (API + MM Agent) - [ ] GitHub Actions CI/CD |
- [ ] Stripe 결제 → 베팅 가능 - [ ] staging 환경 가동 |
| Phase 4 — Final · S10 | - [ ] ZK 탐색 (optional, 타임박스) - [ ] UI polish - [ ] 공개 demo 영상 - [ ] README 최종 - [ ] 회고 문서 ( docs/history/) |
- [ ] Demo Day |
총 예상: ~25–35일 집중 작업 (캘린더로는 회복일 / 외부 대기 / 비-코딩 작업 포함해서 6–8주 정도가 현실적).
해석 가이드
planning 브랜치 history에 보존 — SDK/CLI 모양은 S2에 그대로 carry over.§1.4 표는 step 단위 (S1..S10)만 정의함. 한 step (특히 S2) 안의 작업을 시간 순서대로 나눠 추적할 때는 history doc에서 S<step>.<n> 형식의 sub-step 라벨을 비공식 컨벤션으로 사용. plan에 first-class entity는 아니고, 작업 단위 cross-reference 용.
현재 사용 중인 S2 sub-step 매핑 (S2 row의 deliverable 불릿을 시간 순서로 분해):
| 라벨 | 작업 단위 | 첫 등장 |
|---|---|---|
| S2.1 | Gnosis CTF 분석 (research note + Foundry cycle 테스트) | history.md 2026-05-11 |
| S2.2 | Polymarket CTF Exchange import + Gnosis CTF deploy | history.md 2026-05-11 |
| S2.3 | CTF order fill end-to-end (Foundry-level + anvil 데모 스크립트) | history.md 2026-05-26 |
| S2.4 | SDK 표면 전환 — buyYes/buyNo → fillOrder/signOrder (EIP-712) |
history.md 2026-05-13 |
| S2.5 | MM Agent v0 (paper-trading minimum maker) | history.md 2026-05-13 |
| S2.6 | CLI을 order-based flow로 갱신 | history.md 2026-05-13 |
운영 규칙:
[Frontend]
↓
[API Server]
↓
[Event System (Pub/Sub or Kafka)]
↓
[Indexer Workers]
↓
[PostgreSQL]
↘ Blockchain (EVM)
↑
[MM Agent] ← 별도 워커 프로세스
메인 백본 (S2부터):
핵심 기능:
fillOrder / fillOrders — 매수/매도 (off-chain order의 on-chain 체결)signOrder (EIP-712) — 클라이언트 단에서 order 서명splitPosition, mergePositions, redeemPositions — outcome token 회계reportPayouts (UMA 또는 owner) — 마켓 정산Phase 1 S1의 parimutuel scaffold (Market.sol, MarketFactory.sol)는 SDK/CLI 모양 검증용 학습 패스였고 메인 백본은 아님 (planning 브랜치 history 참고).
역할:
주요 엔드포인트:
GET /markets
GET /markets/:id
GET /positions/:user
Blockchain event → DB 저장.
PostgreSQL (Cloud SQL).
디자인 방향: Polymarket-style CLOB UI (S3부터 실데이터)
UI 레이아웃과 시각적 밀도는 Polymarket 메인 피드 스타일 — 카드 그리드 피드, 카테고리/검색 네비게이션, 멀티해상도 마켓 그룹화, 트렌딩 사이드바, 추천 마켓 hero 카드.
S3에 Web MVP가 들어올 시점엔 이미 S2의 CTF Exchange 백본이 작동 중이므로, 호가창·시계열·다해상도 확률 차트 모두 실데이터로 동작한다. (S1 parimutuel scaffold는 backend가 못 채우는 요소가 있었으나 메인 백본 아님 — §4.5 참고.)
차용 범위: layout/density/카드 구조에 대한 영감만. 브랜드 컬러, 타이포, 카피, 아이콘 세트는 자체 결정 (Polymarket의 시각 identity를 그대로 복사하지 않음).
UI 레퍼런스 (한국어 로컬라이즈, 2026-05-07):

원본 파일: packages/web/public/mockups/polymarket-reference.png
기능:
마켓 resolve를 누가/어떻게 결정하는가에 대한 단계적 도입. 각 stage가 새로운 oracle 컨트랙트 주소를 가지므로 마켓 생성 시 쓸 oracle을 선택 (prepareCondition(oracleAddr, ...)). 같은 마켓의 oracle을 사후 변경할 수 없음 — 새 마켓은 새 oracle 사용.
| Stage | 시점 | Oracle | 사용 케이스 | 한계 |
|---|---|---|---|---|
| 1. Manual | S2~ | 운영자 EOA | 모든 종류 (수동) | 운영자가 SPOF (§11.3 A5). 빠르지만 신뢰 의존 |
| 2. Chainlink adapter | S6 first | ChainlinkOracleAdapter 컨트랙트 |
숫자 마켓 — 가격, 통계 등 “ETH > $4000 by 2027-01-01” | Chainlink가 인덱싱하는 수치만. 주관적 질문 불가 |
| 3. UMA adapter | S6 second | UMAOptimisticOracleAdapter 컨트랙트 |
이벤트/뉴스 — “Did Brazil win the World Cup?” | 응답 지연 (분쟁 윈도우). 분쟁 시 escalation 비용 |
채택 순서가 manual → Chainlink → UMA인 이유: 신뢰 가정의 점진적 분산. Manual은 단일 운영자 전제 (가장 빠른 출시); Chainlink는 분산된 oracle 네트워크지만 데이터 종류 제한; UMA는 분쟁 가능 + 사람 attestation으로 임의의 명제도 다룸 (가장 강한 보증, 가장 큰 시스템 복잡도).
같은 종류 마켓에 여러 oracle 가능: “ETH > $4000?” 마켓을 stage 1엔 manual로 한 번, stage 2엔 Chainlink로 한 번 만들 수 있음 (서로 다른 conditionId). UI가 어느 마켓이 어느 oracle인지 표시.
0002-aa-strategy.md — §11.4 B2)기본 기능:
EIP-7702 기반 사용자 대면 기능 (S7~S8 산출):
선택된 AA 전략이 EIP-7702 또는 hybrid일 때 활성화:
approve(USDC) + fillOrder 1 서명. 기존 2~3 팝업 흐름 → 1 서명.redeemPositions를 사용자가 잊어도 backend scheduler가 자동 호출. 사용자 EOA에 ONLY redeemPositions 허용하는 최소 delegate (audit-grade) 사용.자세한 구현·결정 항목은 §11.4 참고.
자동화된 마켓 메이커 봇. 별도 워커 프로세스로 실행되며 SDK를 통해 컨트랙트와 상호작용한다.
목적
핵심 기능
범위 (초기)
범위 (제외, 후속)
기술 스택
@verex/sdk 사용 (직접 컨트랙트 호출 금지 — SDK 경유로 일관)GitHub Actions.
Market/MarketFactory + SDK + CLI. SDK/CLI 구조 검증을 위한 학습 패스. (planning 브랜치 history.)fillOrder)packages/mcp-server 스캐폴딩Historical note (2026-05-11 갱신): 이전 plan은 Phase 1 (S1~3)을 v1 (fixed-price escrow), Phase 2 S6에 v2 (CTF) 전환으로 두었음. 운영자 prior CTF 경험을 반영해 v2를 S2부터 메인 백본으로 당김. S1의 parimutuel
Market/MarketFactory코드는 SDK/CLI 모양 검증용 학습 패스로planning브랜치 history에 보존 — 메인 라인은 S2의 CTF Exchange + Gnosis CTF + USDC.
무엇이 S1에서 S2로 carry over하나
createFactoryClient + createMarketClient) — 이름은 유지, 내부 구현이 CTF로 교체됨scripts/sync-abis.mjs) — forge 산출물 → TS const, 그대로 사용create/buy/... → create/fill/...로 변경되지만 패키지 구조는 동일S1 코드 자체와 v1 보안 audit 발견은 Phase 1 S1 implementation note (2026-05-07-phase1-w1-implementation.md) 와 v1 Security Audit (2026-05-08-v1-security-audit.md) 에서 historical record로 추적됨.
idquestionendTimeresolvedresultusermarketIdside (YES/NO)amountusermarketIdyesAmountnoAmountmarketIdside (YES/NO)pricesizetsmarketIdyesExposurenoExposurerealizedPnlunrealizedPnlcreateMarketresolveclaimmonorepo는 pnpm workspaces + Turborepo 기반.
verex/
├── packages/
│ ├── contracts/ # Foundry, Solidity 0.8.24
│ ├── sdk/ # TypeScript, viem — 컨트랙트 wrapper
│ ├── api/ # Fastify REST API
│ ├── web/ # Next.js 14 dApp
│ └── mm-agent/ # 신규: 자동 마켓 메이커 워커
│ ├── src/
│ │ ├── index.ts # CLI 엔트리
│ │ ├── runner.ts # 메인 루프 (poll → quote → submit)
│ │ ├── strategy.ts # 가격/사이즈 결정
│ │ ├── inventory.ts # 포지션 추적
│ │ ├── risk.ts # 한도 및 서킷 브레이커
│ │ └── config.ts # market별 설정 로더
│ ├── test/
│ ├── package.json
│ └── README.md
├── docs/
│ ├── principles/ # 설계 원칙, 요구사항 (이 문서)
│ ├── plans/ # phase별 실행 계획
│ └── history/ # 의사결정 로그
├── package.json
├── pnpm-workspace.yaml
└── turbo.json
원칙
@verex/sdk 경유.Market, Side)은 sdk에서 export하여 web/api/mm-agent가 함께 사용.확정되지 않았지만 추적해야 할 요구사항. 설계가 무르익으면 본문 섹션으로 승격한다.
의도
1차 후보 하네스: OpenClaw
보조 옵션 (병행 검토)
Verex × OpenClaw skill (초안)
사용자의 OpenClaw에 설치되는 skill이 노출할 도구:
list_markets, get_market(id) — 읽기, 키 불필요buy_yes / buy_no(market, amount) — 서명 필요claim(market) — 서명 필요subscribe_market(id) — 종료/정산 시 OpenClaw 채널로 알림 push읽기는 @verex/sdk로 RPC만 치면 되고, 쓰기는 §2.2.8 AA + session key 위임이 전제.
해결해야 할 질문
다음 액션
packages/openclaw-skill/ 폴더 추가 검토 (skill 매니페스트 + tool 정의)CTF Exchange는 이제 S2 메인 백본 (§1.4 / §4 Phase 1). 더 이상 planning 트랙이 아니라 implementation 트랙. 본 절에 있던 결정 항목들은 S2 진입 시점에 코드/ADR로 해소됨:
planning 브랜치 history로 보존, deprecate 별도 작업 없음fillOrder/fillOrders) → S2 산출물 (§1.4)Historical context: 이전 §11.2는 “v2를 S6에 시작할지” 결정 항목을 추적했음. 2026-05-11에 S2로 당기는 결정 후 trim. 자세한 전환 배경은 §4.5 참고.
셀프 리뷰 산출물:
docs/analysis/2026-05-08-v1-security-audit.md. 본 절은 그 audit에서 추적이 필요한 액션 항목만 모음.
리뷰 결과 요약: HIGH 0 / MEDIUM 1 / LOW 2 / INFO 6. v1 발견의 ~70%는 v2 (Phase 2 S6 — CTF + UMA) 도입으로 자동 해소.
액션 항목 (트리거 시점별)
| # | 항목 | Severity | 트리거 시점 | 위치 |
|---|---|---|---|---|
| A1 | PRIVATE_KEY env fallback 제거 — vm.envOr → vm.envUint |
INFO | testnet/staging deploy 직전 | packages/contracts/script/Deploy.s.sol:18 |
| A2 | CLI에 chainId 가드 추가 (anvil 31337만 허용) |
INFO | S2 진입 시 함께, 늦어도 testnet 진입 전 | packages/cli/src/clients.ts |
yesPool > 0 && noPool > 0 확인 |
OBSOLETE (v1 parimutuel-only) — S2 CTF는 별도 풀 개념 없음 | n/a | ||
MarketFactory.getMarkets() pagination |
OBSOLETE (v1-only) — S2 CTF는 다른 레지스트리 패턴 | n/a | ||
| A5 | 단일 글로벌 owner SPOF — 별도 mitigation 없이 S6 UMA 도입에 의존 | MEDIUM | S6 UMA 통합 시 자동 해소 | n/a — 추적만 |
원칙: v1 자체 hardening은 더 이상 우선순위 아님 (S1 코드는 history). A1/A2는 S2 작업 + testnet 진입 시점에 함께 처리, A3/A4는 v1-only라 obsolete, A5는 S6 UMA가 해소.
상세 (severity 판단 근거, mitigation 분석, v2 매핑): audit 문서 §2 ~ §5 참고.
풀 리서치 노트:
docs/analysis/eip-7702-research.md. 본 절은 그 노트에서 추적이 필요한 결정·액션만 모음.
한 줄 컨텍스트: EIP-7702는 EOA가 특정 트랜잭션에서 임시로 컨트랙트 코드를 빌려 실행할 수 있게 하는 표준. 별도 스마트 계정 배포 없이 배치 실행 / 가스 스폰서십 / 소셜 복구 같은 AA 핵심 기능을 EOA에서 직접 제공. ERC-4337 (현 §2.2.8 후보)과 경합·보완 관계.
액션 항목 (트리거 시점별)
| # | 항목 | Priority | 트리거 시점 | 산출물 위치 |
|---|---|---|---|---|
| B1 | 대상 체인의 EIP-7702 지원 상태 검증 (활성화 여부, RPC 호환성, viem 버전 요구사항). 대상 체인은 §2.2.1/§3에서 정해지는 배포 체인 | HIGH | Phase 3 S7 진입 전 | docs/analysis/eip-7702-research.md 갱신 |
| B2 | AA 전략 결정: (a) ERC-4337 only / (b) EIP-7702 only / (c) hybrid | HIGH | S7 시작 시 | §2.2.8 본문 갱신 + ADR docs/history/0002-aa-strategy.md |
| B3 | 배치 트랜잭션 PoC — USDC approve + createPosition 1 서명 |
MEDIUM | S7 PoC 단계 | packages/contracts/src/BatchExecutor.sol (또는 외부 audited contract 채택) |
| B4 | Paymaster 가스 스폰서십 PoC — 신규 유저 첫 베팅 무가스 | MEDIUM | S7~S8 | packages/api 또는 외부 paymaster 서비스 통합 |
| B5 | DelegateContract 선택 기준 + Revoke 패턴 audit-grade로 정리 | HIGH | 실거래 (testnet 이상) 진입 전 | docs/security/eip-7702-delegate-policy.md |
| B6 | Auto-claim delegate 컨트랙트 — 특정 사용자에 대해 ONLY redeemPositions 허용하는 최소 delegate. 다른 function selector 없음, audit-grade. + backend scheduler가 resolved 마켓 watch |
HIGH | S7 mid-week (S7 AA wallet 구현 후) | packages/contracts/src/AutoClaimDelegate.sol + packages/api의 scheduler 모듈 |
| B7 | Paymaster spend tracker — per-wallet 카운터, 첫 N=5 거래만 후원, N+1번째부터 중단. 저장: off-chain DB vs on-chain mapping 결정 | MEDIUM | S8 시작 시 | 결정 후 — packages/api 또는 packages/contracts/src/PaymasterSpendCap.sol |
| B8 | 모듈러 계정 표준 선택 (B2 하위 결정) — B2가 4337/hybrid로 결정될 경우 스마트 계정의 모듈 표준: ERC-6900 vs ERC-7579 (권고). 계정은 7579 계열 (Nexus/Kernel v3), 인프라 (번들러·페이마스터)는 독립 층이라 Alchemy 유지. 리서치: docs/analysis/erc-6900-vs-7579-research.md |
HIGH | S7 시작 시 (B2와 함께) | ADR 0002-aa-strategy.md에 포함 + features/account-abstraction.md 갱신 |
연결되는 본문 섹션
원칙: Phase 3 진입 전까지는 리서치 단계. 본격 PoC는 S7 시작과 함께. v2 (CTF Exchange) 통합과 별개로 진행 가능 — 단 둘 다 같은 시기에 들어오므로 일정 조정 필요.
“Verex는 Web3 기술을 통합한 실전형 예측시장 플랫폼이다.”