Earn (ERC-4626 Vaults)
Earn lets a user put a shielded balance to work in an ERC-4626 yield vault (for example a Morpho vault) and pull it back out — without the funds ever leaving the shielded pool. A deposit spends a private asset note, routes it through the vault via the external call gateway, and credits the vault shares back as a new private note; a withdraw redeems those share notes the same way. The vault call itself is public on-chain, but the account that owns the deposited note is not.How it works
An earn deposit is a gateway unshield. Instead of paying a private note out to a public address, the SDK signs an authorization that lets the gateway run the vault call and credit the result straight back into the pool:- Preview & authorize. The SDK reads the vault on-chain (
asset(),previewDeposit/previewRedeem), derives aminOutputAmountfloor from your slippage bound, and signs thePB:WITHDRAW:GATEWAYauthorization for exactly that request. - Execute. The gateway spends the input note and calls the vault. The output is measured on-chain, not trusted from the preview.
- Credit. The measured vault output is credited as a new gateway-origin private note. The owner’s identifying keys never appear in the transaction.
- Refund on failure. If the vault reverts, the request expires, or the fill
would land below the signed
minOutputAmount, the input is refunded as a private note via the fallback receipt. Funds never leave the pool uncredited.
SDK API shape
The earn surface lives on the vault resource (sdk.vault). Reads are
public; the two write operations require an authenticated session.
earnDeposit / earnRedeem take an EarnParams. amount is net — exactly
what enters the vault call (assets for a deposit, shares for a redeem); the
unshield fee is charged on top, so your notes must cover amount + fee.
maxSlippageBps bounds the fill below the on-chain preview (default 100 =
1%).
Tracking settlement
An earn operation returns anEarnResult with a requestId. Because the credit
lands in a later epoch than the unshield, poll the unshield status and read
the gateway projection — gateway.creditStatus === 'completed' is the
terminal state. The top-level completed flag only covers the unshield epoch,
not the vault credit.
Vault history charts
getEarnVaultHistory and getEarnVaultCharts return cached TVL and net-APY
series suitable for rendering a chart. Both are public — usable before
login.
metricis'tvlUsd'or'netApy';periodis'1w' | '1m' | '3m' | 'all'(server default1w).getEarnVaultChartsfetches both metrics at once and rejects if either fails — callgetEarnVaultHistorytwice if you want partial results.- APY values are decimal ratios (
0.05= 5%); TVL values are USD. Points ascend by timestamp. - A
nullpoints[].valueis an upstream gap — render it as a gap rather than interpolate across it. - Check
metadata.statebefore presenting the data as current. Today it is one offresh,stale(upstream unavailable — this is the last good series),synthetic(deterministic testnet data), orunsupported. It is an open set: treat an unrecognized state as renderable data of unknown freshness, not an error. - While the server’s cache warms, a cold request may answer
503with a retry-after hint; the SDK’s standard retry policy already honors it.
Trust and privacy
Earn is a deposit-and-credit extension: the gateway can only spend the note you authorize and credit the measured result back into the pool. It grants no new authority to move or seize funds.
A gateway-origin note joins the same shared note tree as every other deposit
and transfer, so its anonymity set is the full mixed pool. Earn hides who
deposited into the vault, not that the vault was used — the vault call
(target and amount) is public on-chain. The
minOutputAmount floor is signed,
so no operator can settle a deposit into a worse-than-authorized fill; the worst
case is a refund of the input.
Launch limitations
These are known constraints of the current (pre-audit) preview; design around them:- Pre-audit. The gateway contracts are outside the completed audit scope until the External Call Gateway Audit Gate clears. Do not custody significant value on it in production before then.
- Enabled per deployment. A deployment without a gateway has no
externalGatewayAddressin/info, andgetGatewayConfig()returnsenabled: false. Always feature-gate onenabledand the operation’savailability.canSubmitvalue. - Operator-curated catalog. Only vaults the operator approves are usable.
listEarnVaults()reports per-operation availability and any warnings — honor them before offering a deposit. - Slippage is a floor, not a guarantee of execution. A fill below the signed
minOutputAmountrefunds the input via the fallback receipt instead of executing; surface that outcome rather than treating the request as failed. - History is a best-effort cached read. Freshness is reported by
metadata.state, and a cold cache can briefly503. Do not treat astaleor unknown state as an error. - Single-chain. Earn works on a chain that hosts both a pool and a deployed gateway.
Using it from the SDK
- TypeScript / WASM — the earn methods on
sdk.vault. See the TypeScript API reference. - CLI — the
earnsubcommands. See the Commands reference. - iOS / Android / React Native — the earn deposit/redeem and catalog methods
plus JSON-passthrough history reads (
getEarnVaultHistoryJson,getEarnVaultChartsJson), matching the existing earn read surface.