> ## Documentation Index
> Fetch the complete documentation index at: https://www.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# getYieldEarnings

# getYieldEarnings

Gets a wallet's [Earn](https://www.dynamic.xyz/docs/earn/overview.md) earnings across every vault it holds on one chain: aggregate USD totals plus a per-vault breakdown.

For Morpho and Kamino vaults, the values are indexed by the provider rather than read on-chain, so they trail the chain head by a short delay. [`getYieldPosition`](https://www.dynamic.xyz/docs/javascript/reference/client/get-yield-position) stays the source of truth for what a position is worth right now; use this function for earnings and PNL. Providers aggregate per chain, so `chainId` is required. Morpho Vault V1 positions are not covered.

The response combines positions from every provider on the chain, which depends on the wallet account's chain family: an EVM wallet account returns Morpho and Aave positions, and a Solana wallet account returns Kamino positions.

Providers differ in what they report for a position:

* **Morpho** reports PNL and a time-weighted return, so `pnl`, `pnlUsd`, and `roe` are all set.
* **Kamino** reports PNL but no time-weighted return, so `pnl` and `pnlUsd` are set and `roe` is always `null`.
* **Aave** reports no cost basis, so `pnl`, `pnlUsd`, and `roe` are `null`. The entry still carries `assets` and `assetsUsd`.

Positions without PNL add to `totalAssetsUsd` and add nothing to `totalPnlUsd`, so `totalPnlUsd` covers only positions from providers that report it.

Aggregate totals come back in USD only, because per-vault earnings are denominated in different underlying assets and are not additive. 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 `null` for those entries.

> [!WARNING]
>
> Pass a `chainId` from the same chain family as `walletAccount`. An EVM wallet account takes an EVM chain ID, and a Solana wallet account takes the Solana network ID. A mismatch, or a chain that has no earnings data, is rejected with an HTTP 400 error. Solana earnings are available on mainnet only.

## Usage

```javascript theme={"system"}
import { getYieldEarnings } from '@dynamic-labs-sdk/client';

const earnings = await getYieldEarnings({
  chainId: 8453, // Base
  walletAccount,
});

console.log(earnings.totalPnlUsd); // aggregate PNL in USD
console.log(earnings.vaults.length); // per-vault breakdown
```

## Parameters

| Parameter | Type | Description |
| - | - | - |
| `chainId` | `number` | Chain ID on which the wallet's earnings are aggregated: an EVM chain ID (e.g. `8453` for Base), or the Solana network ID (`101` for mainnet), the same value [`listYieldVaults`](https://www.dynamic.xyz/docs/javascript/reference/client/list-yield-vaults) returns as `chainId` for a Solana vault. |
| `walletAccount` | `WalletAccount` | The wallet account whose earnings are being read. An EVM or a Solana wallet account, matching `chainId`. |
| `client` | `DynamicClient` (optional) | The Dynamic client instance. Only required when using multiple Dynamic clients. |

## Returns

`Promise<YieldEarnings>` - The wallet's aggregate USD totals and per-vault earnings.

| Field | Type | Description |
| - | - | - |
| `chainId` | `number` | The chain the earnings were aggregated on. |
| `ownerAddress` | `string` | The wallet address the earnings were read for. |
| `totalAssetsUsd` | `number` | Total position value across vaults, in USD. |
| `totalPnlUsd` | `number` | Total profit or loss across vaults whose provider reports it, in USD. |
| `vaults` | `YieldVaultEarnings[]` | Per-vault earnings entries. |

Each entry in `vaults`:

| Field | Type | Description |
| - | - | - |
| `vaultId` | `string \| null` | Opaque vault identifier, or `null` for vaults the environment does not offer. |
| `vaultAddress` | `string` | Address of the vault: a contract address for an EVM vault, or an account address for a Solana vault. |
| `assets` | `string` | Current position value in raw underlying-token units. Divide by `assetDecimals` before display. |
| `assetsUsd` | `number \| null` | Position value in USD, or `null` when the vault has no USD price. |
| `pnl` | `string \| null` | Profit or loss in raw underlying-token units. Negative for a loss. `null` when the provider does not report a cost basis. |
| `pnlUsd` | `number \| null` | Profit or loss in USD, or `null` when the vault has no USD price or the provider does not report a cost basis. |
| `roe` | `number \| null` | Time-weighted, non-annualized return as a decimal. `null` when there is too little history, and always for Aave and Kamino, which report none. |

## Examples

### List per-vault earnings

```javascript theme={"system"}
import { getYieldDetails, getYieldEarnings } from '@dynamic-labs-sdk/client';
import { formatUnits } from 'viem';

const earnings = await getYieldEarnings({ chainId: 8453, walletAccount });

for (const vault of earnings.vaults) {
  if (vault.vaultId === null || vault.pnl === null) {
    continue; // vault not offered here, or no PNL available (for example, the provider reports no cost basis)
  }

  // `pnl` is a raw string in the vault's underlying-token units, like `assets`
  // from getYieldPosition, so format it with the vault's `assetDecimals`.
  const details = await getYieldDetails({ vaultId: vault.vaultId });
  const pnl = formatUnits(BigInt(vault.pnl), details.assetDecimals);
  console.log(`${details.assetSymbol}: ${pnl} (${vault.pnlUsd ?? 'n/a'} USD)`);
}
```

### Read a Solana wallet's earnings

```javascript theme={"system"}
import { getYieldEarnings } from '@dynamic-labs-sdk/client';

// `solanaWalletAccount` is a Solana wallet account.
const earnings = await getYieldEarnings({
  chainId: 101, // Solana mainnet
  walletAccount: solanaWalletAccount,
});

for (const vault of earnings.vaults) {
  // Kamino reports no time-weighted return, so `roe` is always null here.
  console.log(vault.vaultAddress, vault.pnlUsd, vault.roe);
}
```

## React

`useGetYieldEarnings` is a query hook that stays disabled until `walletAccount` is defined, safe to render before a wallet is connected.

```tsx theme={"system"}
import { useGetYieldEarnings } from '@dynamic-labs-sdk/react-hooks';
import type { WalletAccount } from '@dynamic-labs-sdk/client';

function TotalEarnings({
  chainId,
  walletAccount,
}: {
  chainId: number;
  walletAccount: WalletAccount | undefined;
}) {
  const { data: earnings, isLoading } = useGetYieldEarnings({
    chainId,
    walletAccount,
  });

  if (isLoading) {
    return <p>Loading earnings...</p>;
  }

  return <p>Total PNL: ${earnings?.totalPnlUsd.toFixed(2) ?? '0.00'}</p>;
}
```

## Related

* [`getYieldPerformance`](https://www.dynamic.xyz/docs/javascript/reference/client/get-yield-performance) - The wallet's earnings in a single vault
* [`getYieldPosition`](https://www.dynamic.xyz/docs/javascript/reference/client/get-yield-position) - The wallet's current balance in a vault
* [`listYieldVaults`](https://www.dynamic.xyz/docs/javascript/reference/client/list-yield-vaults) - The vaults available to the environment


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.