From b2bfcb552943a26b98bee02f7a5469a333fa320a Mon Sep 17 00:00:00 2001 From: jhfnetboy Date: Thu, 2 Jul 2026 11:27:39 +0700 Subject: [PATCH] docs: config/dependency inventory + replay & recovery verification runbook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_AND_DEPENDENCIES.md: full inventory of YAA's secrets/private keys, endpoints/services, and chain config, each tagged for the zero-backend target — eliminate (server secret → relay/API-key), user-configurable (AAStar default OR your own = decentralization choice), dev-only (must not ship), or runtime flag. Feeds beta security hygiene + the config-center design. REPLAY_AND_RECOVERY_VERIFICATION.md: beta-pre #3 (replay) + #1 (recovery) are live/integration flows (funded account, KMS, 2-day timelock) — records the protection mechanism (single-use challenge + 10min TTL + EntryPoint nonce; guardian flow + timelock) and an owner runbook with verified-by-design vs needs-live-run status. --- docs/CONFIG_AND_DEPENDENCIES.md | 75 ++++++++++++++++++++++++ docs/REPLAY_AND_RECOVERY_VERIFICATION.md | 58 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 docs/CONFIG_AND_DEPENDENCIES.md create mode 100644 docs/REPLAY_AND_RECOVERY_VERIFICATION.md diff --git a/docs/CONFIG_AND_DEPENDENCIES.md b/docs/CONFIG_AND_DEPENDENCIES.md new file mode 100644 index 0000000..587b1b3 --- /dev/null +++ b/docs/CONFIG_AND_DEPENDENCIES.md @@ -0,0 +1,75 @@ +# YAA — Config, Resources, Keys & Dependencies Inventory + +> What YetAnotherAA actually depends on: secrets/private keys, endpoints/services, chain +> config. Feeds two things: (1) **beta security hygiene** (dev keys must not ship), and +> (2) the **zero-backend / decentralization** design — which of these can be user-configured +> ("use AAStar's or your own") vs which must be *eliminated* (relay + API-key model). +> Date: 2026-07-02. Source: `aastar/.env` + `aastar-frontend/.env.local` + code. + +Disposition legend for the zero-backend target: +- 🔴 **Eliminate** — a server-only secret; remove via the relay + API-key model (never in a browser). +- 🟢 **User-configurable endpoint** — AAStar default OR the user's own (decentralization choice). +- 🟡 **Dev/test only** — must NOT be present in a production/beta build. +- ⚙️ **App/runtime flag** — non-secret configuration. + +## 1. Secrets & private keys (backend `aastar/.env`) + +| Key | Purpose | Disposition | +|---|---|---| +| `JWT_SECRET` | signs the app session JWT | 🔴 → auth root becomes passkey/KMS session (drop server JWT) | +| `USER_ENCRYPTION_KEY` | AES-256 at-rest encryption (32 chars) | 🔴 → client-side encryption keyed off passkey/KMS | +| `KMS_API_KEY` | KMS access (injected by the `/kms-api` proxy) | 🔴 → replaced by the **user's own API key** (direct KMS) | +| `PIMLICO_API_KEY` | ERC-4337 bundler | 🔴 → user's key / public/sponsored bundler | +| `DEPLOYER_PRIVATE_KEY` (config `deployerPrivateKey`; not in current .env — maps from `ETH_PRIVATE_KEY` or unset) | relays passkey **account deploy** (`submitCreateWithPasskey`) | 🔴 → **AAStar relay service** (see `RELAY_SERVICE_PROPOSAL.md`) | +| `ETH_PRIVATE_KEY` | relays **recovery** `executeRecovery()` on-chain | 🔴 → relay service (same pattern as deploy) | +| `RESEND_API_KEY` | email OTP send | 🔴/drop → OTP optional; passkey is primary | +| `ETHERSCAN_API_KEY` | explorer lookups | 🟢 optional / user-configurable | +| `TELEGRAM_BOT_TOKEN` | ops liveness alerts (monitor) | 🔴 ops-only (never client) | +| `DATA_TOOLS_PASSWORD` | `/data-tools` admin gate | 🔴 admin-only | +| `PRIVATE_KEY`, `PRIVATE_KEY_{JASON,ANNI,BOB,BROWN,CHARLIE,JACK,SUPPLIER}`, `TEST_PRIVATE_KEY` | **test EOAs** for L1 scripts | 🟡 **dev-only — must not ship to beta/prod** | +| `BLS_TEST_PRIVATE_KEY_1/2` (+ node ids/pubkeys) | BLS test-node keys | 🟡 dev-only | + +> Beta gate: confirm the 🟡 dev keys are absent from any deployed `.env` (readiness DoD #8: +> "codebase secret scan clean"). The 🔴 set is what the relay + API-key model removes. + +## 2. Endpoints / external services (🟢 user-configurable in the zero-backend model) + +| Config | Service | AAStar default | Self-config? | +|---|---|---|---| +| `ETH_RPC_URL` / `SEPOLIA_RPC_URL{,2,3}` / `RPC_URL` | chain RPC | publicnode / infura | 🟢 own RPC | +| `BUNDLER_RPC_URL` / `PIMLICO_BUNDLER_URL` / `CANDIDE_BUNDLER_URL` | ERC-4337 bundler | Pimlico (via key) | 🟢 own bundler | +| `KMS_BASE_URL` / `KMS_ENDPOINT` / `KMS_PROXY_URL` / `NEXT_PUBLIC_KMS_URL` | KMS (WebAuthn ceremonies + signing) | `kms.aastar.io` / `kms1.aastar.io` | 🟢 own/community KMS | +| BLS signer network (`NEXT_PUBLIC_BLS_SEED_NODE`, DVT nodes) | BLS aggregate signatures | `yetanotheraa-validator.onrender.com`, `dvt1/2/3.aastar.io` | 🟢 own signer set | +| (proposed) `RELAY_URL` | account-deploy relay | `relay.aastar.io` / SuperRelay | 🟢 own relayer | +| `BACKEND_API_URL` / `NEXT_PUBLIC_API_URL` | app backend (goes away in zero-backend) | `127.0.0.1:3000` | n/a (removed) | + +> **Decentralization choice (user request):** every 🟢 row is "AAStar default **or** your own". +> The client already supports KMS/bundler URL overrides (`lib/api-key-store.ts`, on the +> migration branch); the config page extends this to RPC + RELAY. Blank = AAStar default; +> filled = self-hosted. Code supports self-config; AAStar defaults are a convenience, not a lock-in. + +## 3. Chain / contracts (⚙️ mostly canonical, not secrets) + +~148 `*_ADDRESS` / `*_FACTORY` / `CHAIN_ID` / `ENTRY_POINT_*` / `VALIDATOR_*` / `AIRACCOUNT_*` / +`PAYMASTER_*` vars. Most resolve from **`@aastar/sdk` canonical** (`getCanonicalAddresses(chainId)`); +`.env` only overrides. Includes: EntryPoint v0.6/0.7/0.8, AAStar account factory/impl/extension, +validator router, BLS aggregator, SuperPaymaster, PaymasterV4, registry, GToken, aPNTs. Per-chain +(Sepolia now; Optimism mainnet for the phase-2 release). + +## 4. Runtime flags (⚙️) + +`NODE_ENV`, `PORT`, `NETWORK`, `CHAIN_ID`, `KMS_ENABLED`, `DB_TYPE` (json/postgres), +`DEFAULT_ENTRYPOINT_VERSION`. + +## 5. Summary — what the zero-backend + relay design does to this list + +- **🔴 secrets → eliminated** from the app: KMS/bundler via the **user's API key**; account-deploy + + recovery via the **AAStar relay service** (billed in aPNTs); JWT/encryption via a + passkey/KMS-rooted client session. No private key in the app/browser. +- **🟢 endpoints → user-configurable**: RPC / KMS / bundler / relay — AAStar default or self-hosted + (the decentralization choice), surfaced in the config page. +- **🟡 dev keys → must be stripped** before beta (security hygiene). +- **⚙️ chain/contracts → canonical from the SDK**, per-network. + +This is the config target the config-center page (`app/settings`) manages: **endpoints + the +user's own API key only — never private keys.** diff --git a/docs/REPLAY_AND_RECOVERY_VERIFICATION.md b/docs/REPLAY_AND_RECOVERY_VERIFICATION.md new file mode 100644 index 0000000..35254df --- /dev/null +++ b/docs/REPLAY_AND_RECOVERY_VERIFICATION.md @@ -0,0 +1,58 @@ +# Beta-pre verification: replay rejection + social recovery + +> Two beta-pre negatives that are **live/integration** flows (need a funded account, KMS, +> and — for recovery — an on-chain timelock), so they can't be deterministic headless +> tests. This records the protection **mechanism** (grounded in code) + an **owner runbook** +> to verify on Sepolia, with status. Date: 2026-07-02. + +## 1. Replay rejection (challenge / nonce) — beta-pre #3 + +**Mechanism (already in place, by design):** +- The prepared transfer handle is **single-use with a ~10-min TTL** — `transfer.service.ts` + ("The prepared handle is single-use and ~10min TTL"). The KMS `/SignHash` ceremony + **consumes** the `ChallengeId`; reusing it is rejected. +- The UserOp **EntryPoint nonce** is monotonic on-chain; replaying a landed UserOp with a + used nonce reverts (AA25). +- The challenge itself is the **WYSIWYS commitment** over the exact payload, so it can't be + re-pointed at a different transfer. + +So replay protection is enforced at the **KMS (challenge consumption) + EntryPoint (nonce)** +layers, not in app code — there is no app-level unit test that meaningfully covers it. + +**Owner runbook (Sepolia, funded passkey account):** +1. Transfer page → prepare + submit a small transfer; confirm it lands (tx on-chain). +2. Capture the `challengeId` from the prepare response (devtools/network). +3. Re-POST `/transfer/submit` with the **same** `challengeId` + credential → + **expect rejection** (challenge consumed / TTL). ✅ = replay blocked. +4. Also: after a successful transfer, retry the exact prepared op → expect nonce/AA25 reject. + +**Status:** mechanism ✅ (code-confirmed); end-to-end run ⬜ (owner, live). + +## 2. Social recovery — beta-pre #1 + +**Flow (backend `guardian.controller.ts`):** `guardian/add` → `recovery/initiate` → +`recovery/support` (guardian co-sign) → **on-chain 2-day timelock** → `recovery/execute` +(backend relayer sends `executeRecovery()`), plus `recovery/cancel` and +`recovery/:accountAddress` (status). P256 (passkey) guardian path: +`recovery/p256/prepare` + `recovery/p256/submit`. + +**Existing runbook:** `docs/social-recovery-e2e-test.md` (3 MetaMask guardians, full steps ++ expected results). The **only slow part is the 2-day on-chain timelock** before `execute`. + +**Recommended split for beta:** +- Verify NOW (fast, no timelock): add/remove guardian, `recovery/initiate`, guardian + `support`/co-sign, `recovery/cancel`, status endpoint, and **replay/unauthorized + rejections** (non-guardian can't support; can't execute before timelock; can't replay a + used recovery). These prove the flow + its guards without waiting. +- `recovery/execute` happy path requires the **2-day timelock** — schedule one full run + (initiate → wait 2 days → execute) before the OP-mainnet release (phase 2). + +**Status:** design ✅ + runbook ✅; fast-path e2e ⬜ (owner); full timelock run ⬜ (owner, phase 2). + +## 3. Beta recommendation + +Neither is deterministically testable headless. For beta: +- **Replay:** mechanism is sound (KMS single-use + nonce); do the owner runbook once on + Sepolia to confirm, then ship. +- **Recovery:** run the **fast-path + rejection** checks before beta; **gate the full + timelocked recovery as "experimental" in beta** and complete the 2-day run before mainnet.