Skip to main content

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.
Preview feature — pending external audit. The External Call Gateway (Earn) moves user funds through operator-approved external targets and ships to mainnet only after a gateway-specific security audit (see the External Call Gateway Audit Gate in AUDIT_SCOPE.md). Treat the API as stable-but-unaudited and gate production use on your own review. Earn is enabled per deployment: the server advertises the executor as externalGatewayAddress in /info only when the gateway is enabled. Detect support at runtime with sdk.vault.getGatewayConfig(), which returns the executor address, request constraints, and availability. Deployments without a gateway return enabled: false; feature-gate on that field and the relevant availability.

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:
  1. Preview & authorize. The SDK reads the vault on-chain (asset(), previewDeposit / previewRedeem), derives a minOutputAmount floor from your slippage bound, and signs the PB:WITHDRAW:GATEWAY authorization for exactly that request.
  2. Execute. The gateway spends the input note and calls the vault. The output is measured on-chain, not trusted from the preview.
  3. Credit. The measured vault output is credited as a new gateway-origin private note. The owner’s identifying keys never appear in the transaction.
  4. 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.
A withdraw is the mirror image: it redeems share notes and credits the asset output.

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 an EarnResult with a requestId. Because the credit lands in a later epoch than the unshield, poll the unshield status and read the gateway projectiongateway.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.
  • metric is 'tvlUsd' or 'netApy'; period is '1w' | '1m' | '3m' | 'all' (server default 1w). getEarnVaultCharts fetches both metrics at once and rejects if either fails — call getEarnVaultHistory twice if you want partial results.
  • APY values are decimal ratios (0.05 = 5%); TVL values are USD. Points ascend by timestamp.
  • A null points[].value is an upstream gap — render it as a gap rather than interpolate across it.
  • Check metadata.state before presenting the data as current. Today it is one of fresh, stale (upstream unavailable — this is the last good series), synthetic (deterministic testnet data), or unsupported. 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 503 with 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 externalGatewayAddress in /info, and getGatewayConfig() returns enabled: false. Always feature-gate on enabled and the operation’s availability.canSubmit value.
  • 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 minOutputAmount refunds 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 briefly 503. Do not treat a stale or 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 earn subcommands. 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.