Current-state snapshot: what's done, in flight, next, risks. Keep current — see
PROCESS.md. History is inLOG.md.
Last updated: 2026-07-10
Phase: Framework v5 + component refactor + reusable kits (2026-07-10). The framework's
guts are a #[starknet::component] ShardComponent; ConfidentialShard is a thin frozen
embedder (upgradeability = opt-in fork, never the blessed contract). v5 removed the framework
salt (commitment = poseidon(logic, app_state)), which is what makes the escape hatch
MALICIOUS-operator-safe (the operator no longer holds a secret blinding). Reusable importable
modules: salt_kit (deterministic blinding), crypto_kit (STARK-curve ECIES), da_kit
(in-circuit encrypted DA) + SDK da.ts. Lending → v3 (salt_kit). New da_kit example
PrivateRegisterLogic (blind-party encrypted DA). counter is the transparent opt-out example.
Deep audit done (2026-07-10): framework/kits/crypto-core CLEAN; all 7 findings were in the
lending example — the 5 exploitable/design ones are fixed (signer-scoped collateral, repay-
wins-over-expiry, zero-price guard, lender cancel), 2 noted (inbox-spam DoS, stranded
intent-fee). 53 snforge tests + typecheck green. Earlier: committee outbox demo + lending loan
cycle ran end-to-end on Sepolia (v4, historical). Purpose: showcase (see DESIGN preamble).
One-line state: v5 stack builds + 53 tests green off-chain (framework component, salt removed, salt_kit/crypto_kit/da_kit modules, lending v3 audit-fixed, PrivateRegister da_kit example). New v5 class hashes (cairo.md; LendingLogic 0x5c6b4697…). Pre-v5 Sepolia deployments (counter 0x6bb61654…, committee 0x34132247…, lending run) are historical on the v4 framework. No open blockers; a Sepolia demo on the v5 stack + re-audit of the refactor/crypto are the natural next steps.
- Architecture designed and settled — see
../../DESIGN.md. - v1 monolithic
ConfidentialCounter— verified end-to-end on Sepolia (declare → deploy → prove → apply_transition → CAS). Confirmed the SNIP-36 unknowns against a real proof. - Deep security audit of v1 — 0 Critical/High/Medium; both findings later fixed (see below).
- v2 generic framework (
ConfidentialShard) — frozen dispatcher + logic-agnostic verifier; confidentiallogic_class_hashin the committed state;library_callto the committed logic; self-governing upgrades + immutability ratchet. - Reference logic:
CounterLogic— an immutable dummy, checkedu128; ships no upgrade path. - TypeScript SDK (
orchestration/src/,confidential-shard-sdk0.3.0): typed genericLogic<State,Action>(logic.ts) as the app-author boundary;Shard<S,A>lifecycle handle (shard.ts:deployShard/attachShard/genesisOf, one.transition(action)runs prove→pre-check→apply→consume + advances typed state, plusdeposit/registerIntent); pluggableShardBackend(backend.ts) withStrkdBackendreference impl (strkd-backend.ts, owns nonce/ref-block/manual-bounds); pureencoding.tscore (byte-identical to Cairo);apps/counter.ts+apps/committee.tsreferences;index.tsbarrel. Runs undernode --experimental-strip-types(no build step). Typecheck clean; pure-core smoke test passes. Validated on-chain (2026-07-06): drove the committee outbox demo end-to-end viaattachShard+Shard.transition. Fixed a read-RPC race (confirmRootnow polls the post-apply root instead of a single immediate read). - Cairo authoring kit (
src/logic_kit.cairo+src/logics/template_logic.cairo) — pure helpers (build_call,erc20_transfer_call,unseen_inboxproven-read) + a commentedILogicskeleton to copy. Not part of the frozen framework; covered bytests/logic_kit.cairo. - v3 public interaction (outbox) — transitions read public state (proven against the SNIP-36 reference block) and emit public calls:
apply_transitionrecordsposeidon(Serde(actions))to the outbox; permissionless one-shotconsumere-supplies + hash-checks + dispatches. Root advances regardless of settlement. See../../DESIGN.md"Public interaction (v3)". - Fixed both audit findings — #1 salt reuse (per-transition rotation), #2 ungated reference upgrade (
CounterLogicmade immutable). - Deep re-audit of the framework (v2, pre-v3) — 0 Critical/High. Confirmed:
library_callcan't spooffrom_address, sole-emitter holds, logic is commitment-pinned, framework is frozen. - 2026-07-03 first-principles design review — docs corrected (false tight-accounting claim removed; risk register refreshed for v3 stakes); pre-freeze inventory identified and then decided with the user (see LOG).
- v4 public → shard (inbox) + pre-freeze surface — all four decided items landed: (a) inbox:
deposit(token, amount, note)(framework-executedtransfer_from→ trustless attribution) +register_intent(payload)(≤ 64 felts, optional per-shard anti-spam fee paid to the shard) +inbox_len/inbox_entryproven-read views; consumption = confidential cursor in the logic's app_state, never a framework flag. (b)outbox_of(key)view — settlement observability (honest reserved-balance accounting is now possible). (c) freshness gate — per-shard constructor param, default off;⚠️ proof_facts[4]unverified, do not enable before the Sepolia experiment. (d)outputsechoed inTransitioned— the indexable (encrypted-)DA channel. Escape hatch: decided none (exits are logic-level). See../../DESIGN.md"Inbox (v4)". -
CommitteeLogicreference (replaces the removedVaultLogic, which was an uninstructed example) — confidential M-of-N committee: threshold stark-curve approvals verified in-proof (shard- and nonce-bound; signatures ride inpublic_input, seen only by the prover), emits the approved arbitrary calls through the outbox. Immutable. -
LendingLogicreference — confidential P2P lending PoC (0x7602ac88…): one shard = one loan. min/max LTV committed-but-hidden ⇒ liquidation price unknowable in advance. OFFERED (Alice escrows USDC) →take(Bob's collateral read from inbox; hidden bandminLTV ≤ draw/(coll·price) < maxLTVenforced in-proof vs oracle; outbox pays Bob) →close(one method; branch forced by facts: repay ⇒ collateral→Bob + principal+interest→Alice; else price-cross OR past-due ⇒ liquidate collateral→Alice). Flat interest + duration; freshness gate ON for loan shards (stale-price defense). Useslogic_kit. Design (user-decided): single-operator (Charlie holds state), hide LTV only (amounts public; V2 → strk20 privacy pool), min=yield-floor/max=liquidation, collateral→lender. Escape hatch — BUILT (v2, 2026-07-09): every transition carries a SNIP-12 signature verified in-proof (take=borrower;close=any of operator/lender/borrower), so Alice or Bob can settle without Charlie; the successor state is echoed encrypted (hybrid ECIES to each party's key,src/crypto.ts) viaoutputsso any party can decrypt + self-prove (verifiedcommit==root). Guards unchanged (auth only says WHO). New class0xef3a907b…. Sepolia escape run pending. Mocks:MockToken(multi-holder,0x5d7a8f95…),MockOracle(0x1b32ae46…). SDK appapps/lending.ts. Sepolia end-to-end DONE (2026-07-08): 3 role accounts (Alice/Bob/Charlie), mock USDC/strkBTC/oracle deployed, loan shard0x77e51db3…(freshness gate on); ran offer → Alice escrow 40k → Bob collateral 1 BTC → TAKE (Bob +30k at hidden 60% LTV) → Bob repay 33k → CLOSE (Alice 43k = principal + 3k interest, Bob's 1 BTC returned). LTV params never touched chain. See [[lending-poc]] / LOG. - snforge tests — 40 passing (lending v2 = 11: take band + below/above-LTV rejects, escape: borrower self-close-after-repay / lender self-liquidate-on-expiry / price-liquidate, + unauthorized-signer / bad-signature / healthy rejects, SNIP-12 cross-check) (incl. 2 audit regressions: cross-chain approval replay, deposit received-delta; + 3
logic_kittests: call builders +unseen_inboxagainst a real shard):CounterLogic(increment/immutability/overflow) +CommitteeLogic(threshold approval → actions, below-threshold / duplicate-signer / non-member / stale-nonce rejects) + frameworktransition(commit determinism,library_calldispatch incl. committee end-to-end with real signatures, salt rotation, zero-salt reject) +consume(executes, double-consume/hash-mismatch/self-call rejects,outbox_ofpending→settled) + inbox (register_intent/depositappend + read-back, payload cap, zero-deposit reject, intent fee charged, global ordering, out-of-range reject).apply_transition's proof_facts path (incl. the freshness gate) is Sepolia-only, as before.
- (nothing currently in flight) — v3+v4 surface implemented, tested, and deep-audited (2026-07-03).
Framework (2026-07-02):
- ✅ FIXED — Medium (conf 78) constant salt reuse: per-transition caller-supplied
new_salt(assert != 0); SDKfreshSalt(); guard + rotation tests. - ✅ FIXED — Low (conf 55) ungated upgrade in reference
CounterLogic: upgrade path removed; no reference ships one.
v3+v4 deep audit (2026-07-03, deep mode: 5 agents incl. adversarial; 0 Critical/High; all 3 notes below the 75 confidence threshold, all resolved):
3. ✅ FIXED — Medium (conf 70) committee approval missing chain-id (committee_logic.cairo): approval_hash now includes get_tx_info().chain_id, blocking replay onto an identically-addressed shard on another network. SDK approvalHash mirrors it; regression test committee_rejects_cross_chain_replay.
4. ✅ FIXED — Medium (conf 68) deposit recorded nominal amount (framework.cairo): now records the measured balance_of delta (fee-on-transfer / rebasing safe), asserts non-zero received. Needed a balance_of add to the framework IERC20. Regression test deposit_records_actual_received_delta_not_nominal.
5. ✅ DOCUMENTED — Low (conf 55, adversarial) consume ignores callee return (framework.cairo): a non-reverting-false ERC-20 is treated as settled and the entry can't be replayed. Can't be fixed generically (opaque return ABIs); documented the revert-on-failure requirement + "don't treat outbox_of()==0 as proof of effect" in the consume doc comment.
CommitteeLogic SNIP-12 rewrite audit (2026-07-06, focused adversarial pass on the one changed file; 0 Critical/High): binding (shard/nonce/chainId/calls), dedup, threshold, strict 'VALID', fail-closed on bad/undeployed signers, and Serde parsing all confirmed sound.
6. ✅ DOCUMENTED — Low (blind-signing): the SNIP-12 message carries calls_hash, not decoded calls, so a wallet shows a hash not the action. Off-chain mitigation (SDK derives calls_hash from the reviewed calls) documented in the logic comment + committee.ts; a production committee wanting wallet-decodable approvals should enumerate calls in the typed message.
- ✅ DONE (2026-07-06) — Outbox demo on Sepolia (
CommitteeLogic→consume). strkd shipped thewallet_signTypedData↔ SNIP-12 fix (+ new key-freecompanion_typedDataHash); confirmed by hash-match and an on-chainis_valid_signature='VALID'. Then ran m1+m2 approve → prove → apply →consumethrough the SDK: the 2-of-3 committee moved 0.05 STRK out of shard0x34132247…via the outbox (nonce 0→1, root0x5bd72f0f…,outbox_ofcleared to 0). First fully confidential private→public settlement on-chain. (Genesis salt recovered from the prior scratchpad; the per-transition salt rotation means a further transition needs a known salt or a fresh deploy.) 1b. (done 2026-07-06)Fresh Sepolia deploy + reference-age experiment— completed; see Artifacts + LOG.proof_facts[4]=ref block number and[5]=block hash confirmed; a 118-block-stale reference was accepted at apply (gate off) → freshness gate is load-bearing. Inbox deposit verified. - DA plan for non-toy state: for multi-party shared state, the decided direction is encrypted on-chain DA (logic-level: ciphertext of the new state/diff in
outputs, computed in-proof, hash-bound; now indexable via theTransitionedevent). Worth packaging as a reusable Cairo component (Poseidon-keystream encrypt + append to outputs) when the first multi-party logic is built. - Multi-party exit-fairness logic pattern — the committee reference demonstrates authorization; a full multi-party pool logic would add: encrypted-DA publishing, inbox-intent servicing rules (exit requests), and reserved-balance accounting via
outbox_of. Design pass needed before building (state-channel-grade adversarial reasoning). - (If/when upgrades are wanted) ship a gated upgradeable logic as a separate example — e.g. the committee's threshold machinery applied to a member-rotation / logic-upgrade directive.
- The framework MUST stay frozen (no
replace_class/admin/rootsetter). Load-bearing for logic-immutability. The v4 surface landed before any real deploy precisely because frozen means never-addable; the surface is now considered final. (consumeonly replays proven bundles; the v4 constructor params are per-instance genesis config with no setters.) - Outbox is non-atomic (accepted, user decision): the root advances even if an outbox entry never settles. Keeping the ledger honest is a logic choice; with v4's
outbox_of, honest reserved-balance accounting is now possible (track unsettled keys in app_state, prove settlement) — but no shipped reference does balance accounting (CommitteeLogicis authorization-based). See [[outbox-vs-atomic-actions]]. - DA loss = locked funds: a shard holds real ERC-20s; losing the off-chain state (or a bricking upgrade) permanently locks them — no escape hatch exists, by explicit decision (2026-07-03). Mitigation is logic-level: encrypted on-chain DA (the chain becomes the backup) — see DESIGN "Inbox (v4)".
- Freshness gate — verified (2026-07-06):
proof_facts[4]IS the reference block number and[5]the block hash (confirmed on Sepolia). The protocol does NOT enforce a tight reference-age window (a 118-block-stale reference applied fine on a gate-off shard), so a shard that needs exit fairness MUST setfreshness_window > 0; the gate index is correct. - Inbox spam: junk entries inflate honest proving cost (logics read past them). Mitigations: per-shard intent fee (dark knob, default 0), payload cap (64), logic-level processing caps / dust thresholds.
- Confidentiality boundary: any public call (a
consumed action) is public; deposits and intents are public; transition timing + message shapes fingerprint the application (see the 2026-07-03 review — behavioral fingerprinting means which-logic privacy is thin for bespoke logics). What stays confidential: state contents, decision inputs, WHO approved (committee). - Bricking by bad upgrade is accepted (user decision): fail-closed stall; framework only asserts
next != 0. - Phase-1 SNIP-36 trust model (sequencer-side verification): a sequencer accepting a false proof can write a
rootwhose preimage it chose, then drain shard-held funds through the outbox. Do not anchor real value under Phase 1. (Related, accepted: SNIP-36 proofs are aspirationally ZK — not yet witness-hiding; accepted knowingly 2026-07-03.) - v3+v4 surface deep-audited 2026-07-03 (0 Critical/High; 3 below-threshold notes fixed/documented — see Open audit findings). Residual:
apply_transition's proof_facts path (incl. freshness gate) + on-chainconsumeare network-only-testable, pending the Sepolia deploy.
Framework class hashes (current build, 2026-07-03):
| Class | Hash |
|---|---|
ConfidentialShard |
0x54d35d6bde0f4abf8f2ca63c6647ca15c3152655913eb838da5df1e1c56997c |
CounterLogic |
0x1acb3488cfe126eb7d06bdd445bed46006768097be9791f2632912921e5feb5 |
CommitteeLogic (SNIP-12/is_valid_signature, 2026-07-06) |
0x3e08859c716af05769f71285fce006435d863e1047696d302d78171ae8b5e6a |
v4 Sepolia deployment (2026-07-06):
- Agent account (funder/submitter):
0x04078aa88fd37258ad019413af8ba35c509e701c984aaaa2c41c3834f4363906 ConfidentialSharddeclared: class0x54d35d6b…(tx0x70e5d1a2…);CounterLogicdeclared:0x1acb3488…(tx0x2e7e66d5…).- CounterLogic shard:
0x6bb61654c22e728c5efc9ed74053e4b7caaedb5e43e08ae445b4507f2bbd36(deploy tx0x373cb6d5…, UDC, gates off: freshness 0 / fee 0). - genesis_root
0x31647b99…(count 0) → transition 10x57047366…(count 1, apply tx0x100076eb…) → transition 20x65bbd855…(count 2, apply tx0x473259cc…, proven against 118-block-stale ref). - Inbox deposit: 1 STRK, tx
0x3ae58401…;inbox_entry(0)= DEPOSIT / caller = agent account / [STRK, 1e18, 0, note 0xc0ffee].
Committee (SNIP-12) outbox demo (2026-07-06, COMPLETE — see backlog #1):
CommitteeLogicre-declared: class0x3e08859c…(tx0x4649997a…).- Members: m1 = main
0x04078aa8…(signer), m2 =0x050fdb8f…(index 7, deployed, signer), m3 =0x06147515…(index 8, counterfactual non-signer). - 2-of-3 committee shard:
0x34132247dc05a498c301141c83c6ebb589ed727f89f4cb67396f1f416c70ada(genesis0x5a253eb7…, gates off), funded 1 STRK. Demo executed: committee approved a 0.05 STRK transfer → main; after apply+consume the root is0x5bd72f0f78071b9fb96049dab549b8f68facea79921003c7e1a846d00007205(nonce 1) and the shard holds 0.95 STRK. consume tx0x58fb4a8f…. - Confirmed proof_facts:
[0]=0x50524f4631 'PROOF1',[1]='VIRTUAL_SNOS',[4]=ref block number,[5]=ref block hash,[7]=1,[8]=message hash.
v1 monolithic deployment (Sepolia, historical): contract 0x285b651f…, class 0x7c0bbb31…, account 0x04078aa8… (see LOG.md).