Repository navigation
Perch policy-document integration: doc-only smart accounts, policy UI, and account recovery #207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
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 28bf582
docs: promote CLAUDE.md to AGENTS.md; record perch doc-layer knowledge
willemneal ce95220
no-mistakes(review): fix doc network binding, decompile u32 edge, tri…
willemneal 793007d
chore(sdk): consume published perch npm packages, drop interim plumbing
willemneal 6472737
fix(lockfile): scope perch swap to perch entries only, drop churn
willemneal 45c13e0
fix: remove stray packages/perch/dist committed during the npm swap
willemneal e3e8883
spike(contracts): hybrid perch apply_doc on the smart account
willemneal 9000b54
spike(sdk): buildApplyDocTx + three-tier readPolicy
willemneal 856e258
spike(contracts+sdk): store canonical doc JSON on-chain; view-first r…
willemneal 9737ee6
spike(contracts): doc-only — apply_doc is the sole policy write path
willemneal 464f6b0
spike(sdk+frontend): doc-only — buildApplyDocTx is the only apply route
willemneal ae8acff
spike(deploy): doc-only smart-account + factory live on testnet
willemneal 1270af6
spike(fix): align compiler wire types to the DEPLOYED artifact; fixtu…
willemneal 7c8d77b
spike(deploy): realigned wasm live on testnet; add-admin apply verifi…
willemneal 1979dca
spike(caps): re-enable capped docs on perch compiler 0.2.1
willemneal af32be7
feat(frontend): policy inspector + builder for a smart account
willemneal 605eda5
feat(frontend): perch-powered policy inspector + doc-mode builder
willemneal b927fc9
feat(frontend): dApp-requested scoped session key via policy document
willemneal 4986a4f
fix(frontend): align doc read with the SDK's view-first readPolicy in…
willemneal 9f530ca
test(e2e): @fast UI specs for the policy page and delegate-doc request
willemneal b06b70a
docs(agents): point at the frontend's policy-doc surface
willemneal 583642f
feat(frontend): doc-only policy writes + document-update diff preview
willemneal 72d9126
fix(frontend): reconcile with the doc-only base — anti-brick baseline…
willemneal 31a8358
feat(frontend): admin-key add/remove in the policy builder
willemneal 40a7144
fix(frontend): policy-page navigation + readable doc previews
willemneal 1e90ce3
fix(frontend): convert the legacy passkey delegate flow to doc-only
willemneal fb059f1
feat(frontend): admin keys as one any-may-act list (captain ruling: o…
willemneal 7fb48a9
feat(frontend): founder signer id owner → admin (captain naming ruling)
willemneal 410b8c8
feat(frontend): fresh accounts get a doc view — synthesized baseline,…
willemneal 89b5260
spike: recovery Stage 1 - transition spec + reference model
willemneal c1210ea
spike: recovery Stage 2 - completion mechanism experiment
willemneal a26a118
spike: recovery Stage 3 - guardian/ZK/combined controller, real proofs
willemneal 582d5b8
ci: add recovery-controller/recovery-verifier to Scout audit matrix
willemneal a880a04
spike: recovery Stage 3 - client SDK, proof-gen CLI, experimental UI
willemneal ff6b704
fix(recovery-stage3): verify account wiring before enroll; add config…
willemneal f00f96f
docs(recovery-stage3): confirm live that every factory account is pre…
willemneal 2be7e8e
fix(bindings): restore @nidohq/recovery-controller package name/version
willemneal 12711ff
docs(recovery-stage3): document the wiring precondition and config_ha…
willemneal 0aba4a8
fix(recovery): route friend/guardian recovery UI to Stage 3 (retire l…
willemneal aabc428
fix(recovery): let ZK and guardian recovery converge on Combined mode
willemneal c5ca622
Merge remote-tracking branch 'origin/fm/nido-recovery-stage3-n8' into…
willemneal 4d868f3
Merge remote-tracking branch 'origin/fm/nido-pr168-showcase-n2' into …
willemneal 99dc232
docs: present recovery + doc-only work as one coherent feature, not s…
willemneal 31133f4
test(e2e): live smoke of the combined policy page + a real apply_doc
willemneal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should also add:
There was a problem hiding this comment.
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).