Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
08ec9ec
feat(sdk): perch PolicyDoc doc layer — build, lower, decompile
willemneal Sep 9, 2026
28bf582
docs: promote CLAUDE.md to AGENTS.md; record perch doc-layer knowledge
willemneal Sep 9, 2026
ce95220
no-mistakes(review): fix doc network binding, decompile u32 edge, tri…
willemneal Sep 9, 2026
793007d
chore(sdk): consume published perch npm packages, drop interim plumbing
willemneal Sep 9, 2026
6472737
fix(lockfile): scope perch swap to perch entries only, drop churn
willemneal Sep 9, 2026
45c13e0
fix: remove stray packages/perch/dist committed during the npm swap
willemneal Sep 9, 2026
e3e8883
spike(contracts): hybrid perch apply_doc on the smart account
willemneal Sep 10, 2026
9000b54
spike(sdk): buildApplyDocTx + three-tier readPolicy
willemneal Sep 10, 2026
856e258
spike(contracts+sdk): store canonical doc JSON on-chain; view-first r…
willemneal Sep 10, 2026
9737ee6
spike(contracts): doc-only — apply_doc is the sole policy write path
willemneal Sep 10, 2026
464f6b0
spike(sdk+frontend): doc-only — buildApplyDocTx is the only apply route
willemneal Sep 10, 2026
ae8acff
spike(deploy): doc-only smart-account + factory live on testnet
willemneal Sep 10, 2026
1270af6
spike(fix): align compiler wire types to the DEPLOYED artifact; fixtu…
willemneal Sep 10, 2026
7c8d77b
spike(deploy): realigned wasm live on testnet; add-admin apply verifi…
willemneal Sep 10, 2026
1979dca
spike(caps): re-enable capped docs on perch compiler 0.2.1
willemneal Sep 10, 2026
af32be7
feat(frontend): policy inspector + builder for a smart account
willemneal Aug 8, 2026
605eda5
feat(frontend): perch-powered policy inspector + doc-mode builder
willemneal Sep 10, 2026
b927fc9
feat(frontend): dApp-requested scoped session key via policy document
willemneal Sep 10, 2026
4986a4f
fix(frontend): align doc read with the SDK's view-first readPolicy in…
willemneal Sep 10, 2026
9f530ca
test(e2e): @fast UI specs for the policy page and delegate-doc request
willemneal Sep 10, 2026
b06b70a
docs(agents): point at the frontend's policy-doc surface
willemneal Sep 10, 2026
583642f
feat(frontend): doc-only policy writes + document-update diff preview
willemneal Sep 10, 2026
72d9126
fix(frontend): reconcile with the doc-only base — anti-brick baseline…
willemneal Sep 10, 2026
31a8358
feat(frontend): admin-key add/remove in the policy builder
willemneal Sep 10, 2026
40a7144
fix(frontend): policy-page navigation + readable doc previews
willemneal Sep 10, 2026
1e90ce3
fix(frontend): convert the legacy passkey delegate flow to doc-only
willemneal Sep 11, 2026
fb059f1
feat(frontend): admin keys as one any-may-act list (captain ruling: o…
willemneal Sep 12, 2026
7fb48a9
feat(frontend): founder signer id owner → admin (captain naming ruling)
willemneal Sep 13, 2026
410b8c8
feat(frontend): fresh accounts get a doc view — synthesized baseline,…
willemneal Sep 13, 2026
89b5260
spike: recovery Stage 1 - transition spec + reference model
willemneal Sep 13, 2026
c1210ea
spike: recovery Stage 2 - completion mechanism experiment
willemneal Sep 14, 2026
a26a118
spike: recovery Stage 3 - guardian/ZK/combined controller, real proofs
willemneal Sep 14, 2026
582d5b8
ci: add recovery-controller/recovery-verifier to Scout audit matrix
willemneal Sep 14, 2026
a880a04
spike: recovery Stage 3 - client SDK, proof-gen CLI, experimental UI
willemneal Sep 14, 2026
ff6b704
fix(recovery-stage3): verify account wiring before enroll; add config…
willemneal Sep 14, 2026
f00f96f
docs(recovery-stage3): confirm live that every factory account is pre…
willemneal Sep 14, 2026
2be7e8e
fix(bindings): restore @nidohq/recovery-controller package name/version
willemneal Sep 14, 2026
12711ff
docs(recovery-stage3): document the wiring precondition and config_ha…
willemneal Sep 14, 2026
0aba4a8
fix(recovery): route friend/guardian recovery UI to Stage 3 (retire l…
willemneal Sep 14, 2026
aabc428
fix(recovery): let ZK and guardian recovery converge on Combined mode
willemneal Sep 14, 2026
c5ca622
Merge remote-tracking branch 'origin/fm/nido-recovery-stage3-n8' into…
willemneal Sep 14, 2026
4d868f3
Merge remote-tracking branch 'origin/fm/nido-pr168-showcase-n2' into …
willemneal Sep 14, 2026
99dc232
docs: present recovery + doc-only work as one coherent feature, not s…
willemneal Sep 14, 2026
31133f4
test(e2e): live smoke of the combined policy page + a real apply_doc
willemneal Sep 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .github/workflows/scout.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ jobs:
- factory
- multisig-policy
- name-registry
- recovery-controller
- recovery-verifier
- smart-account

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should also add:

  • preauth-sweep-policy
  • recovery-doc-completion

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — recovery-doc-completion and preauth-sweep-policy were both missing from the Scout matrix. Fixing this as part of the branch-stack rebuild (recovery-doc-completion lands with the recovery layer; preauth-sweep-policy is an unrelated pre-existing gap I'm fixing alongside it since I'm already touching this file).

- spending-limit-policy
- status-message
Expand Down
142 changes: 142 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Nido helps users move from Stellar G-addresses to Soroban Smart Accounts (C-addresses) using WebAuthn/passkey authentication. All passkey verification is on-chain via the WebAuthn verifier contract and OpenZeppelin's stellar-accounts library.

## Build & Test Commands

```bash
just test # cargo test --workspace
just build # cargo build --workspace (native)
just build-contracts # stellar contract build --optimize (Soroban wasm)
just check # cargo fmt --check + cargo clippy -D warnings
just fmt # cargo fmt --all
```

Run a single test by name: `cargo test -p nido-integration-tests smart_account_check_auth_with_passkey`

## Workspace Architecture

Three contracts plus integration tests:

**`contracts/smart-account`** — Soroban contract implementing OpenZeppelin's `CustomAccountInterface` + `SmartAccount` + `ExecutionEntryPoint` traits. Delegates auth to `do_check_auth` from stellar-accounts. `#![no_std]`.

**`contracts/webauthn-verifier`** — Soroban contract implementing OZ's `Verifier` trait for secp256r1/P-256 passkey signature verification. Stateless — deploy once, shared across accounts. `#![no_std]`.

**`contracts/factory`** — Deploys Smart Accounts with a WebAuthn signer. Lazy-deploys a shared verifier instance.

**`crates/integration-tests`** — Cross-crate integration tests using synthetic P-256 keypairs to construct full WebAuthn assertions without a browser.

## Policy doc layer (perch)

The perch PolicyDoc is nido's policy source of truth at the doc layer:
`packages/passkey-sdk/src/policyDoc/` builds docs, lowers them onto OZ context
rules (stock policies where the shape fits, the perch interpreter otherwise),
and decompiles chain rules back to a doc view — its module docs are the
authoritative reference. Perch comes from npm (`@stellar-registry/perch`,
`@stellar-registry/perch-interpreter`; a root `overrides` entry keeps the
interpreter bindings on the workspace's single `@stellar/stellar-sdk` copy —
the #72 dual-SDK hazard). Perch contract addresses are derived, not deployed
by nido — see DEPLOYED.md "Perch canonical deployment" and
`src/policyDoc/deployment.ts`; frozen golden vectors live in
`src/policyDoc/testdata/`. The frontend's doc surface lives under
`packages/frontend/src/lib/policy/` (three-tier read, doc builder drafts,
the dApp delegate-doc request contract) — each module's header comment is
the reference.

## Frontend Design Export

`packages/frontend/scripts/export-design.mjs` exports the built site into
`packages/frontend/design-export/` as self-contained single-file HTML pages (CSS
inlined, all `<script>` tags stripped, internal links rewritten to flat
filenames). Use it to hand a page off for visual design editing (e.g. paste into
a Claude.ai artifact) or browse the whole site's styling offline via
`design-export/_index.html`.

```bash
cd packages/frontend && npm run build && node scripts/export-design.mjs
```

It's a static snapshot of *design*, not a running app: the landing page
(`index.html`) is fully static, but the app screens are stateful views whose
content JS injects at runtime — so dynamic data shows as placeholders/skeletons.
Pages whose UI lives inside `class="hidden"` mode containers need their primary
state revealed; the script's `reveal` map handles this (currently un-hides
`#home-mode` on the account page). Add an entry there if another page exports blank.

## Account recovery (guardian quorum + ZK)

Guardian-quorum and ZK-proof account recovery for doc-only smart accounts,
built in three layers that are still visible in the code/doc layout:

**Transition spec** (`docs/recovery/TRANSITION_SPEC.md` +
`packages/recovery-spec/`) — the state-machine transition spec, an
executable reference model, and adversarial tests for Perch/Nido ZK+guardian
recovery, per `firstmate/data/perch-zk-recovery-scout-p5/follow-up.md`. No
contracts or circuits here — read the spec doc before extending recovery
design elsewhere.

**Completion mechanism** (`docs/recovery/stage2-findings.md`,
`contracts/recovery-doc-completion`,
`crates/integration-tests/tests/it/recovery_stage2_*.rs`) compares two ways
to complete a doc-hash-committed recovery attempt against the doc-only smart
account: authorizing the existing `apply_doc` (Variant A, adopted — no
smart-account code changes) vs. a dedicated `complete_recovery` entry point
sharing the same internal pipeline (Variant B). Read the findings doc's
call-ordering section before adding any recovery completion vehicle — it
explains why a value-bound, single-use completion grant (not a
boolean/ledger flag) is required for any DEDICATED entry point, and why
`apply_doc` needs no such mechanism at all.

**Controller + circuit** (`contracts/recovery-controller`,
`contracts/recovery-verifier`, `circuits/zk_recovery_doc`,
`crates/integration-tests/tests/it/recovery_stage3_*.rs`,
`docs/recovery/stage3-measurements.md`) is the shared controller
implementing guardian-only, ZK-only, and combined evidence paths against the
transition spec's proposal model, completing via the mechanism above's
Variant A. Read `contracts/recovery-controller/src/lib.rs`'s crate doc
comment FIRST — it is the authoritative architecture summary AND the
canonical "Known limits" list (what's NOT implemented and why) before
extending or reviewing this code.

**`circuits/zk_recovery_doc` is a separate circuit crate from the
pre-existing `circuits/zk_recovery` (M1's raw-signer-rotation circuit) —
NOT an in-place edit.** They share domain constants and Merkle/nullifier
logic but bind a different `auth_hash` field list (target-doc-hash instead
of a raw pubkey). Do not merge them or edit one expecting it to affect the
other: `circuits/zk_recovery`'s own fixtures/tests
(`crates/integration-tests/tests/it/zk_recovery_*.rs`, `multisig_recovery.rs`)
pin real `bb`-proved proofs against ITS `auth_hash` formula and would break
if that circuit's witness shape changed. Similarly,
`contracts/recovery-controller/src/zk.rs` deliberately duplicates
(not depends on) `contracts/zk-recovery/src/hash.rs`'s Poseidon2 host-side
reconstruction — same reason.

## Testing Notes

Tests use synthetic P-256 keypairs (`SigningKey::random()`) to construct full WebAuthn assertions without a browser. Contract test IDs use valid stellar-strkey encoded addresses.

## Dependency Version Constraints

- `stellar-accounts` is pinned to a git rev of OpenZeppelin/stellar-contracts to match `soroban-sdk` 25.x

## Relayer channels plugin

`infra/relayer/plugins/channels/index.ts` is a thin passthrough to the upstream
`@openzeppelin/relayer-plugin-channels` handler — it no longer allowlists which
contract function names the relayer will fee-sponsor (removed by design; the
per-function allowlist was a recurring maintenance-friction source, most recently
commit 2533c9a). On-chain auth (the passkey signer on each auth entry) is the only
enforced gate on submitted transactions now — the relayer will fee-sponsor *any*
contract call with valid auth, including calls to contracts other than nido's own.
Do not reintroduce a function-name allowlist here without a captain decision.

## Maintaining this file

Keep this file for knowledge useful to almost every future agent session in this project.
Do not repeat what the codebase already shows; point to the authoritative file or command instead.
Prefer rewriting or pruning existing entries over appending new ones.
When updating this file, preserve this bar for all agents and keep entries concise.
72 changes: 2 additions & 70 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,2 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Nido helps users move from Stellar G-addresses to Soroban Smart Accounts (C-addresses) using WebAuthn/passkey authentication. All passkey verification is on-chain via the WebAuthn verifier contract and OpenZeppelin's stellar-accounts library.

## Build & Test Commands

```bash
just test # cargo test --workspace
just build # cargo build --workspace (native)
just build-contracts # stellar contract build --optimize (Soroban wasm)
just check # cargo fmt --check + cargo clippy -D warnings
just fmt # cargo fmt --all
```

Run a single test by name: `cargo test -p nido-integration-tests smart_account_check_auth_with_passkey`

## Workspace Architecture

Three contracts plus integration tests:

**`contracts/smart-account`** — Soroban contract implementing OpenZeppelin's `CustomAccountInterface` + `SmartAccount` + `ExecutionEntryPoint` traits. Delegates auth to `do_check_auth` from stellar-accounts. `#![no_std]`.

**`contracts/webauthn-verifier`** — Soroban contract implementing OZ's `Verifier` trait for secp256r1/P-256 passkey signature verification. Stateless — deploy once, shared across accounts. `#![no_std]`.

**`contracts/factory`** — Deploys Smart Accounts with a WebAuthn signer. Lazy-deploys a shared verifier instance.

**`crates/integration-tests`** — Cross-crate integration tests using synthetic P-256 keypairs to construct full WebAuthn assertions without a browser.

## Frontend Design Export

`packages/frontend/scripts/export-design.mjs` exports the built site into
`packages/frontend/design-export/` as self-contained single-file HTML pages (CSS
inlined, all `<script>` tags stripped, internal links rewritten to flat
filenames). Use it to hand a page off for visual design editing (e.g. paste into
a Claude.ai artifact) or browse the whole site's styling offline via
`design-export/_index.html`.

```bash
cd packages/frontend && npm run build && node scripts/export-design.mjs
```

It's a static snapshot of *design*, not a running app: the landing page
(`index.html`) is fully static, but the app screens are stateful views whose
content JS injects at runtime — so dynamic data shows as placeholders/skeletons.
Pages whose UI lives inside `class="hidden"` mode containers need their primary
state revealed; the script's `reveal` map handles this (currently un-hides
`#home-mode` on the account page). Add an entry there if another page exports blank.

## Testing Notes

Tests use synthetic P-256 keypairs (`SigningKey::random()`) to construct full WebAuthn assertions without a browser. Contract test IDs use valid stellar-strkey encoded addresses.

## Dependency Version Constraints

- `stellar-accounts` is pinned to a git rev of OpenZeppelin/stellar-contracts to match `soroban-sdk` 25.x

## Relayer channels plugin

`infra/relayer/plugins/channels/index.ts` is a thin passthrough to the upstream
`@openzeppelin/relayer-plugin-channels` handler — it no longer allowlists which
contract function names the relayer will fee-sponsor (removed by design; the
per-function allowlist was a recurring maintenance-friction source, most recently
commit 2533c9a). On-chain auth (the passkey signer on each auth entry) is the only
enforced gate on submitted transactions now — the relayer will fee-sponsor *any*
contract call with valid auth, including calls to contracts other than nido's own.
Do not reintroduce a function-name allowlist here without a captain decision.
<!-- Points Claude at AGENTS.md via import; edit AGENTS.md, not this file. -->
@AGENTS.md
45 changes: 45 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ admin-sep = "0.27.0"
# to a tagged release once one lands on soroban-sdk 27 (latest tag v0.7.2 is 26.1).
stellar-accounts = { git = "https://github.com/OpenZeppelin/stellar-contracts.git", rev = "ec749c3b75971f2c35ced1bea3e2a7e536e91cda", package = "stellar-accounts" }
stellar-registry = "0.1.0"
# Perch policy layer (SPIKE, see PR: applydoc spike). The account's compiler
# WIRE TYPES are no longer taken from perch source at all: the deployed
# canonical compiler on testnet is an older build than any consumable source
# rev (5-field CompiledRule, no cap lowering), so the account mirrors the
# DEPLOYED artifact's spec directly (contracts/smart-account/src/doc.rs) and
# the e2e runs the fetched on-chain bytes
# (crates/integration-tests/fixtures/perch/). Only perch-ir (canonical JSON +
# doc_hash, used by tests to mirror the SDK's canonicalization) remains a git
# dep — pinned to rev f5676a6, the rev the SDK's perch pins mirror.
perch-ir = { git = "https://github.com/stellar-registry/perch.git", rev = "f5676a6cfb7ae02e9ae487be18cf6247653124b0" }
# soroban-sdk-tools 0.1.3 (crates.io) targets soroban-sdk 27, replacing the prior
# BlaineHeffron git fork rev (which existed only to get a soroban-sdk 26 build). We
# now depend on a published, versioned, immutable release rather than an untagged fork.
Expand Down
Loading
Loading