Architecture & Prototype Ideas
Note: produced by myself, Gemini & Claude.
cc: @maurice @graphomath @Michael @ArtemG
- Product: shielded privacy wrapper over Aave v3 that gives each user their own EIP-1167 sub-account proxy, inheriting Aave’s liquidity, interest accrual, and native liquidator network.
- Note: this design addresses both lending and borrowing.
The problem
DeFi lending runs on Aave — billions in liquidity, mature risk parameters, a proven liquidator network — but every position, balance, and liquidation is publicly visible and permanently attached to the user’s address. For enterprises, treasuries, funds, and privacy-conscious users, this transparency is disqualifying.
Three naive approaches fail:
- Rebuild Aave as a native shielded money market — years of engineering, giant audit bill, impossible to bootstrap liquidity from zero.
- Wrap Aave as a shared pool (Aztec Connect model) — works for deposits but catastrophically socializes liquidation risk; one user underwater liquidates everyone. This killed Aztec Connect’s borrowing story.
- Hide collateral, debt, and identity all at once — no protocol has shipped this. Liquidators can’t act on state they can’t see; borrowers don’t self-report when underwater.
Plus: showing the user a $-denominated portfolio view when balances are encrypted notes is non-trivial in any native design.
The solution
A thin wrapper over Aave v3 where each shielded user gets their own EIP-1167 CREATE2 minimal proxy — the exact pattern Instadapp DSA uses in production. Each proxy is an independent Aave borrower with its own health factor, owned by a singleton Forwarder contract that only executes proxy calls when unlocked by a ZK proof from the Anoma Protocol Adapter. The shielded layer’s sole job is hiding the link between user identity and proxy address; everything else — rates, liquidations, accrual, oracles — is delegated to Aave.
Why this solves each problem
| Problem | How the design solves it |
|---|---|
| Rebuilding Aave is infeasible | Wrap it. Day-one liquidity and rates are Aave’s. |
| Aztec Connect’s socialized liquidation | Each user has their own Aave address (the proxy). Alice’s liquidation has zero effect on Bob. |
| Liquidating hidden positions is unsolved | Don’t solve it. Aave’s existing liquidator bots liquidate each proxy natively — they don’t know it’s shielded-owned. Post-liquidation residue stays claimable. |
| Interest accrual in shielded notes | Aave’s liquidityIndex / variableBorrowIndex do the work. The note only commits to a proxy address. |
| Portfolio view from encrypted state | Client-side: decrypt notes → list proxy addresses → call aavePool.getUserAccountData(proxy) and aToken.balanceOf(proxy). Aave multiplies by the index internally. |
| Audit and bootstrap cost | ~300 lines of Solidity + one ZK circuit. Weeks, not months. |
| Borrowing “different” from lending | It isn’t. Same proxy, same resource kind, same action structure. |
Architecture
┌─────────────────────────────────────────────────────────────┐
│ ANOMA EVM PROTOCOL ADAPTER │
│ (verifies ZK proof, then delivers the carrier call) │
└──────────────────────────┬──────────────────────────────────┘
│ onlyAdapter
▼
┌─────────────────────────────────────────────────────────────┐
│ FORWARDER (the Guardian) │
│ │
│ • Holds NO user funds │
│ • Holds NO user→proxy mappings │
│ • Factory: CREATE2-deploys proxies with deterministic salt│
│ • Router: dispatches whitelisted selectors to the proxy │
└──────────────────────────┬──────────────────────────────────┘
│ proxy.delegatecall(impl, selector)
▼
┌─────────────────────────────────────────────────────────────┐
│ SubAccount Proxy (per shielded user) │
│ 45-byte EIP-1167 clone │
│ │
│ HOLDS THE STATE: │
│ • aToken balances (Aave supply position) │
│ • variableDebtToken balances (Aave debt) │
│ • Aave userConfiguration bitmap, eMode │
│ delegatecall-forwards every call to the Implementation │
└──────────────────────────┬──────────────────────────────────┘
│ delegatecall
▼
┌─────────────────────────────────────────────────────────────┐
│ SubAccount Implementation (singleton) │
│ │
│ HOLDS THE LOGIC: │
│ supply / withdraw / borrow / repay / setEMode / sweep │
│ onlyForwarder guard on every entry point │
│ HOLDS NO STATE (delegatecall stores in the proxy's slots) │
└──────────────────────────┬──────────────────────────────────┘
│ pool.supply / pool.borrow / …
▼
┌──────────┐
│ Aave v3 │
└──────────┘
- Forwarder — Singleton per chain. Holds no user funds and no user mappings. Only callable by the Anoma Protocol Adapter after a ZK proof has been verified. Factory (CREATE2-deploys proxies) and router (dispatches whitelisted selectors).
- SubAccount proxy — 45-byte EIP-1167 clone, one per shielded position, owned by the Forwarder. Holds the Aave state: aTokens, variableDebtTokens, userConfiguration, eMode. Deployed lazily on first use (~66k gas).
- Implementation — Singleton logic contract with whitelisted Aave selectors (
supply,withdraw,borrow,repay,setEMode,sweep), guarded byonlyForwarder. Holds no state (delegatecall semantics). - PositionNote resource — The only ARM resource kind.
value_ref = (proxy_address, user_nonce, position_version)whereproxy_address = CREATE2(H(user_nonce || position_version), forwarder). Theuser_noncemust be 256-bit high-entropy (SDK-enforced) to defeat active probing.
Threat-model win: the Forwarder has nothing worth compromising. The user-to-proxy mapping lives only inside the shielded commitment tree, accessible via ZK proof.
Flows
Supply. ARM action carries the input underlying (shielded or public ERC-20) + a calldata-carrier resource targeting Forwarder.executeSupply(salt, pool, asset, amount) + a new or reused PositionNote. The Forwarder lazy-deploys the proxy, funds it, calls Pool.supply(). The proxy now holds scaled aTokens; interest accrues via Aave’s public index with no further user action.
Borrow. Same proxy, same PositionNote. Action carries Forwarder.executeBorrow(...). Forwarder calls proxy.borrow() → Aave checks the proxy’s health factor and mints variable debt tokens. If undercollateralized, Aave reverts, and the whole ARM action reverts. Safety is enforced by Aave’s checks, not re-proved in ZK.
Repay. Similar structure with executeRepay. Full exit composes Repay + Withdraw in one ARM transaction, then nullifies the PositionNote.
Liquidation
Handled entirely by Aave. When a proxy’s HF drops below 1, Aave’s existing liquidator bots call Pool.liquidationCall(..., user=proxy, ...) and seize collateral as they would for any Aave user. The shielded layer never participates. The PositionNote remains valid; its value_ref still points to the same proxy, now with reduced balances, and the residue is sweepable.
The residue sweep is the single worst linkability vector. A public LiquidationCall followed by a shielded sweep in the next few blocks is a near-1:1 correlation. Mandatory client SDK mitigations:
- Sweep Delay — randomized hours-to-days before a residue sweep is allowed.
- Threshold Batcher — only release the sweep after N (≥50) unrelated shielded actions have posted.
- Noise sweeps — protocol-owned sub-accounts perform regular no-op sweep-shaped actions so every real sweep is statistically indistinguishable from a protocol one.
Portfolio view
Pure client-side, zero state reconciliation:
- Decrypt notes from the Adapter’s commitment tree.
- Extract the proxy addresses.
- For each proxy:
aavePool.getUserAccountData(proxy)returns collateral, debt, HF, LTV in USD. Per-asset breakdowns viaaToken.balanceOf(proxy)(Aave already multiplies byliquidityIndexinternally). - Historical P&L reconstructed from Aave’s public event log filtered on
user=proxy.
RPC-level clustering is a silent leak: N sequential queries for N proxies from one IP via one provider let the RPC cluster those proxies together. The SDK must default to split queries across multiple unrelated providers, with optional Tor / mixnet / VPN / local-node transport.
Privacy properties
- Hidden: user identity, the link between an EOA and their proxies, the link between multiple proxies owned by the same user.
- Visible: each proxy’s Aave state (the Railgun Access Card model — private owner, public position), total proxy count, action timing.
- Anonymity set: grows with adoption. Seed with protocol-owned proxies at launch.
Opt-in compliance via voluntary viewing key export. The SDK ships with a “Generate Disclosure” feature using the user’s own viewing key to produce a signed JSON history for tax/audit use. The protocol never holds viewing keys. This frames the product as a privacy layer, not a mixer, and defuses the most common regulatory objection.
Key leaks to mitigate: small launch anonymity set, sweep-after-liquidation timing, salt active probing, RPC clustering, gas payer linkage, withdrawal destination correlation.
Prototype plan
Locked-in decisions: Base first · USDC supply + WETH collateral → USDC borrow · Aave v3 only · keep $500 Adapter beta cap (market as “Safety-First Beta”) · opt-in compliance via viewing key.
- M0 — Spec lock with Anoma team; confirm Adapter constraints; sign off on proxy upgradability (recommendation: beacon proxy for bug-patchability at ~+3k gas/call vs immutable EIP-1167).
- M1 — Solidity contracts (Forwarder + SubAccount + Implementation). Foundry fork-test against live Aave on Base including real liquidation. Solidity audit.
- M2 —
PositionNoteresource logic circuit (Cairo/Noir). ZK-specialist audit. - M3 — Integration on Base Sepolia against the live Protocol Adapter. End-to-end CLI.
- M4 — TypeScript portfolio client with all privacy hygiene features mandatory: CSPRNG nonce generation, split-RPC router, Sweep Delay + Threshold Batcher, Generate Disclosure.
- M5 — Closed beta on Base mainnet. Seed anonymity set with protocol-owned sub-accounts and decoy proxies. Target: 50+ positions, 30+ days, no incidents.
- M6 — Arbitrum + Aave v4 support when v4 lands on L2s.
- M7 — Compound III as a second underlying.
Out of scope: cross-chain atomic borrowing (wait for Anoma cross-controller atomicity), native rate curves, shielded position shape (Ferveo V2), own liquidator network.
Open before M1: proxy upgradability sign-off, Solidity + ZK audit firm selection, formal Anoma team sync, beta whitelist sourcing.
Sources
Aave v3/v4 docs, Compound III docs, EIP-1167, OpenZeppelin Clones, Instadapp DSA, Anoma Resource Machine spec (specs.anoma.net), EVM Protocol Adapter, AnomaPay, Penumbra shielded staking (the exchange-rate-via-public-index pattern, now delegated to Aave), Aztec Connect sunset post-mortem, Railgun Access Cards.