Overview
Earn lets a user’s wallet deposit into a yield vault, track what the position is worth, claim reward campaigns, and withdraw. The earn module on the SDK instance wraps the Earn API and signs and broadcasts the transactions it returns. Vaults run on EVM chains and on Solana, and the module executes an action on whichever chain family its payload targets.
For how vaults, shares, and yield work, see the Earn overview.
Every Earn action returns an unsigned payload. You sign and broadcast it with execute, which sends an EVM payload’s ERC-20 approval first and waits for it to confirm whenever the payload carries one. A Solana payload instead carries an ordered sequence of transactions that execute signs, sends, and confirms one at a time. See Solana vaults.
Prerequisites
- Dynamic SDK initialized (see Quickstart)
- User authenticated (see Authentication)
- A wallet on the vault’s chain family: an EVM wallet for an EVM vault, or a Solana wallet for a Solana vault (see Wallet Creation)
- Earn enabled for your environment in the Dynamic dashboard. Until it is, every call throws an
EarnError with statusCode 403.
Earn is available on the SDK instance as sdk.earn:
Browse vaults
getVaults returns the vaults your environment can access. getVaultDetails adds the on-chain fields you need to display and transact against one, including assetDecimals.
netApy and tvlUsd come from live market data on a best-effort basis, so both are nil when that data is unavailable.
A wallet can only transact on its own chain family, so filter the list by chainName before showing vaults for a wallet:
Read a position
A position holds shares and assets, both in raw token units. Show assets, because it grows as yield accrues. Depending on the vault’s provider, shares either stays flat or always equals assets, so it is not meaningful to show a user.
getVaultPerformance returns a wallet’s earnings in one vault: netEarningsAssets and returnOnCapital. Morpho indexes these values rather than reading them on-chain, so they trail the chain head; getVaultPosition stays the live source of truth for what the position is worth right now.
netEarningsAssets is a raw token-unit string, so divide it by the vault’s assetDecimals before display, the same way you format a position’s assets. returnOnCapital is a time-weighted, non-annualized decimal (for example 0.00413 means a 0.41% return) and is nil while the position has too little history to compute one.
getVaultPerformance currently supports vaults from these providers: Morpho. For a vault from any other provider, such as an Aave vault, the call throws an EarnError with statusCode 400. Use getVaultPosition to show such a position’s balance, and see Provider support.
Read earnings across vaults
getEarnings returns a wallet’s aggregate earnings across every vault it holds on one EVM chain: USD totals plus a per-vault breakdown.
Totals are USD-only, because per-vault earnings are denominated in different underlying assets. A vault with no USD price is skipped from the totals, not counted as zero. Positions in vaults the environment does not offer are still included, with vaultId set to nil for those entries.
Not every provider reports a cost basis for a position. For those vaults, the entry still carries assets and assetsUsd, but pnl, pnlUsd, and roe are nil. Those positions add to totalAssetsUsd and add nothing to totalPnlUsd.
getEarnings covers Morpho and Aave positions on EVM chains. It does not include positions in Solana vaults; read a Solana position with getVaultPosition instead.
Read rewards
Rewards are a separate bonus some vaults pay in another token. They sit unclaimed until you claim them, unlike base yield, which shows up as assets growing.
The list is empty when the wallet has accrued nothing in the vault. Rewards are supported only for vaults from some providers. For a vault from any other provider, the API rejects the rewards and claim requests with an HTTP 400 error, which surfaces as an EarnError. See Provider support.
Deposit
deposit builds the payload, execute sends it. amount is human-readable, so "12.5" deposits 12.5 USDC.
execute returns the vault transaction hash (the last signature on Solana). When an EVM payload carries an evmApproval, it sends that approval first and waits for its receipt, so onStepChange reports .approval before .transaction. An approval is only requested when the vault needs an allowance it does not already have.
To send the shares to a different wallet, set receiverAddress on the request. It defaults to ownerAddress.
Withdraw
Withdrawals redeem shares the wallet already holds, so they never need an approval.
Claim rewards
Solana vaults
A Solana vault action is split into up to three transactions, such as the deposit itself and a step that stakes the deposited shares in the vault’s farm. execute signs, sends, and confirms them one at a time in ordinal order, because a later transaction can depend on the state an earlier one wrote. onTransactionStepChange reports each transaction’s position and label as it begins:
All of an action’s transactions are built against the same blockhash, which stays valid only briefly. If the user takes too long to approve, the remaining transactions expire and execute throws an EarnSolanaStepError. When a later transaction fails or expires, the earlier ones have already confirmed on-chain, so read the wallet’s position with getVaultPosition before retrying. Repeating the whole action could apply the earlier steps twice. See Solana vaults in the Earn overview.
The sponsored parameter on execute picks how the transactions’ fees are paid:
true requires gas sponsorship and throws EarnSponsorError when it is unavailable.
false always pays the fee from the wallet.
nil (the default) sponsors when the environment enables it and falls back to a wallet-paid transaction otherwise.
On EVM, a sponsored execution batches the ERC-20 approval and the vault call into one gasless transaction. On Solana, sponsorship works through SVM Gas Sponsorship; see SVM Gas Sponsorship for how to enable it. Note that an unset sponsored sponsors a Solana action when SVM Gas Sponsorship is enabled, which differs from the JavaScript SDK, where a Solana vault action is wallet-paid unless sponsored is true.
Amount units
Amounts cross the wire as strings in two different units:
- The
amount parameter on deposit and withdraw is human-readable: "12.5" means 12.5 USDC.
EarnVaultPosition, EarnVaultReward, and the amounts inside a signing payload are raw token units. They can exceed Int.max, so they stay strings; convert a position or payload amount with the vault’s assetDecimals, and a reward amount with the reward’s own tokenDecimals, before display.
Mixing the two units up silently transacts the wrong value. Human-readable amounts also need a
leading zero: "0.01" works, ".01" is rejected by the API.
Handle errors
Every failed Earn call throws an EarnError carrying the HTTP statusCode:
execute throws an EarnError when the wallet’s chain does not match the payload’s chain family, when the payload carries no transaction, or when an approval reverts or is not confirmed in time. Two error types are specific to execution:
EarnSolanaStepError carries the ordinal and total of the Solana transaction that stopped and a code of expired, failed, or sendFailed. Transactions before it already confirmed, so check the position before retrying.
EarnSponsorError means sponsored: true was required but sponsorship was unavailable or the sponsored transaction failed.
Next steps