Skip to main content

Earn (ERC-4626 Vaults)

Earn lets a user put a shielded balance to work in an ERC-4626 yield 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.
Earn is a v2 feature enabled per deployment. The server advertises externalGatewayAddress in /info when the gateway is enabled. Use sdk.vault.getGatewayConfig() and each operation’s availability to detect support before offering it.
EARN_VAULT_MODE controls the optional vault metadata catalog, not Gateway execution. A deployment can leave it disabled and still support earnDeposit() and earnRedeem() for ERC-4626 routes advertised by getRegisteredTokens().

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:v2 authorization for exactly that request.
  2. Execute. The pool spends the input note under the epoch proof, and the gateway calls the vault. The output is measured on-chain, not trusted from the preview.
  3. Credit. The measured vault output creates a pending gateway deposit. A later deposit proof credits it as a new 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 recorded as a fallback deposit and credited as a private note by a later deposit proof. 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). Gateway and token capability discovery are public. When configured, catalog and history reads are public too. The two write operations require an authenticated session. Settlement is tracked with sdk.transactions.getUnshieldStatus, which also requires a session. earnDeposit / earnRedeem take an EarnParams. amount is net — exactly what enters the vault call (assets for a deposit, shares for a redeem); the Gateway fee replaces the regular unshield fee and is charged on top, so your notes must cover amount + fee. maxSlippageBps bounds the fill below the on-chain preview (default 100 = 1%).
Before submitting a deposit, also read the vault’s maxDeposit() using gateway.executorAddress as the receiver. A policy-approved route may still have no live capacity; disable deposits when maxDeposit() is below the requested asset amount. The SDK separately validates asset() and reads previewDeposit() or previewRedeem() while building the signed request.

Tracking settlement

An earn operation returns an EarnResult with a requestId. Poll the unshield status and read the gateway projection, since credit lands in a later epoch. gateway.creditStatus === 'completed' means the private note was credited. gateway.creditStatus === 'rescued' is a terminal recovery outcome: the escrow was paid to the rescue destination, so stop waiting for private credit. The top-level completed flag only confirms the original unshield epoch.

Vault history charts

This section applies only when the deployment enables the optional Earn catalog service. With EARN_VAULT_MODE=disabled, catalog and history endpoints are not mounted and return 404; this does not disable Gateway execution. 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. An unprocessed gateway deposit can be rescued after the cancel delay using its designated rescue authority.

Launch limitations

These are constraints of the current implementation:
  • 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-approved routes. Only ERC-4626 calls allowed by the effective Gateway policy and backed by registered pool tokens are usable. Discover those routes from getRegisteredTokens() capabilities. If the optional catalog is enabled, also honor the availability and warnings returned by listEarnVaults().
  • 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 — the earn methods on sdk.vault. See the TypeScript API reference.
  • WASM — the same methods exposed top-level on sdk (sdk.earnDeposit, sdk.earnRedeem, sdk.getGatewayConfig). See the WASM API reference.
  • CLI — the earn subcommands. See the Commands reference.
  • iOS / Android / React Native — earnDeposit / earnRedeem plus typed catalog and history reads (listEarnVaults, getEarnVault, getGatewayConfig, getEarnVaultHistory, getEarnVaultCharts). The *Json variants of the reads remain for callers that parse the wire shape themselves. See the platform API references.