> For the complete documentation index, see [llms.txt](https://docs.kpk.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kpk.io/funds/infrastructure/architecture/onchain-accounting/meta-balance-adapters/wallet-yield.md).

# Wallet Yield

Seventeen immutable meta-adapters that report a wallet-held yield-bearing token (wstETH, sDAI, syrupUSDC, …) as the protocol position it is, at the same balance.

Seventeen immutable meta-adapters, one per protocol, that report a **yield-bearing token held directly in a wallet** (wstETH, weETH, sDAI, syrupUSDC and the like) as the protocol position it actually is, rather than as an anonymous wallet balance. The amount and value are exactly what the [default adapter](/funds/infrastructure/architecture/onchain-accounting/balance-adapters/erc20-default.md) would report; only the identity fields change. Which tokens each adapter covers is a governed instance set on the NAV Calculator.

* **Type:** Meta-adapter (one per protocol, sharing one base)
* **protocolSubId:** one per adapter; see [Adapters](#adapters) below
* **Instance key:** the token address, widened to `bytes32`
* **Source:** `WalletTokenMetaBalanceAdapterBase.sol` · `walletYield/`

## Positions returned

One position per configured token the account holds.

| Leg               | PositionKind            | isDebt  | Description                                 |
| ----------------- | ----------------------- | ------- | ------------------------------------------- |
| Wallet-held token | `Staking` or `Supplied` | `false` | The token's raw wallet balance, unconverted |

The kind is fixed per adapter and follows how the protocol exits at par: `Staking` when exiting means an unstake (a withdrawal queue, cooldown, or validator exit), `Supplied` when it means redeeming deposit or vault shares. A token returns an empty result (rather than reverting) when it is unregistered, excluded by `assetFilter`, or the balance is zero, so one bad token never zeroes out the rest of the set.

## Balance calculation

```
amount = token.balanceOf(account)   // raw balance, no conversion; the token itself is the priced asset
```

The `balanceAsset` is the **token itself**, not an underlying. These tokens are already registered and priced NAV assets, so the pricing path is untouched and the reported value is identical to the default adapter's. This is deliberately unlike the ERC-4626 vault adapters, which convert shares to an underlying because the share is not a registered asset there.

{% hint style="info" %}
**A token is reported by at most one adapter.** Claiming a token as an instance removes it from the default adapter's inclusion list in the same transaction. As a second guard, these adapters report **nothing** for a token the default adapter still includes, so if the two ever disagree the holding is under-reported rather than double-counted. An unreadable answer counts as 'still included'; a check that runs out of gas raises `DefaultAdapterProbeGasExhausted`, which the adapter's instance fan-out re-raises as `InstanceGasExhausted` instead of silently dropping the holding; see [a starved read is not an empty read](/funds/infrastructure/architecture/onchain-accounting/balance-adapters.md#how-an-adapter-is-built).
{% endhint %}

## Identity

* **positionId:** `abi.encode(address token)` (the token address)
* **positionKind:** `Staking` or `Supplied`, per adapter

There is no `labels` field on the position. The adapter implements `positionLabels(positionId)`, which returns `["<category>", "<token symbol>"]` (for example `["LST", "wstETH"]` or `["Savings", "sDAI"]`), collapsing to `["<category>"]` if the symbol cannot be read. It is surfaced only by the verbose reads (`getAccountPositionsVerbose` / `getAccountNavVerbose`); the full breadcrumb is `[protocolName, ...labels]`.

## Adapters

| Adapter                               | Tokens (chain)                                          | PositionKind | `protocolSubId`                | Label category |
| ------------------------------------- | ------------------------------------------------------- | ------------ | ------------------------------ | -------------- |
| `LidoStakedEthWalletMeta`             | wstETH, stETH (1) · wstETH (10, 100, 8453, 42161)       | `Staking`    | `lido-staked-eth`              | LST            |
| `EtherFiStakedEthWalletMeta`          | eETH, weETH (1) · weETH (8453, 42161)                   | `Staking`    | `etherfi-staked-eth`           | LRT            |
| `RocketPoolStakedEthWalletMeta`       | rETH (1)                                                | `Staking`    | `rocket-pool-staked-eth`       | LST            |
| `RenzoRestakedEthWalletMeta`          | ezETH (1, 42161)                                        | `Staking`    | `renzo-restaked-eth`           | LRT            |
| `KelpRestakedEthWalletMeta`           | rsETH (1, 42161)                                        | `Staking`    | `kelp-restaked-eth`            | LRT            |
| `StaderStakedEthWalletMeta`           | ETHx (1)                                                | `Staking`    | `stader-staked-eth`            | LST            |
| `StakeWiseV3OsTokenWalletMeta`        | osETH (1) · osGNO (100)                                 | `Staking`    | `stakewise-v3-os-tokens`       | LST            |
| `LiquidCollectiveStakedEthWalletMeta` | LsETH (1)                                               | `Staking`    | `liquid-collective-staked-eth` | LST            |
| `AnkrStakedEthWalletMeta`             | ankrETH (1)                                             | `Staking`    | `ankr-staked-eth`              | LST            |
| `CoinbaseStakedEthWalletMeta`         | cbETH (8453)                                            | `Staking`    | `coinbase-staked-eth`          | LST            |
| `EthenaSavingsWalletMeta`             | sUSDe (1)                                               | `Staking`    | `ethena-savings`               | Savings        |
| `ReserveBasketsWalletMeta`            | ETH+ (1)                                                | `Supplied`   | `reserve-baskets`              | LST            |
| `SkySavingsWalletMeta`                | sDAI, sUSDS (1) · sDAI (100)                            | `Supplied`   | `sky-savings`                  | Savings        |
| `AaveSavingsWalletMeta`               | sGHO (1)                                                | `Supplied`   | `aave-v3-savings`              | Savings        |
| `SparkSavingsWalletMeta`              | spETH, spUSDC, spUSDT (1)                               | `Supplied`   | `spark-savings`                | Savings        |
| `MapleSavingsWalletMeta`              | syrupUSDC, syrupUSDG, syrupUSDT (1) · syrupUSDC (42161) | `Supplied`   | `maple-savings`                | Savings        |
| `NexusMutualVaultsWalletMeta`         | RWIV (1)                                                | `Supplied`   | `nexus-mutual-vaults`          | Vault          |

Each adapter's `protocolId` is the protocol slug (`lido`, `etherfi`, `sky`, …, with `aave-v3` for Aave and `stakewise-v3` for StakeWise); see the [protocol taxonomy catalogue](/funds/infrastructure/architecture/onchain-accounting/concepts/position-identity.md#protocol-taxonomy-catalogue). Every one takes only the NAV proxy as a constructor argument, so each sits at the **same address on every chain** (★); see [Deployment addresses](/funds/infrastructure/architecture/onchain-accounting/deployment-addresses.md).

## Constructor

```solidity
constructor(address navCalculator_)
```

| Parameter        | Description                                             |
| ---------------- | ------------------------------------------------------- |
| `navCalculator_` | NAV Calculator contract (asset registry + instance set) |

The constructor also resolves the NAV's default adapter once and refuses to deploy (`DefaultAdapterUnresolvable`) if it cannot, since the double-count guard above depends on it.

## Registration

Meta-adapter. Register once and seed its tokens with `addMetaBalanceAdapter(adapter, instances)`, then adjust with `addMetaInstances(adapter, instances)` / `removeMetaInstances(adapter, instances)` (MANAGER-gated). Each instance coordinate is a **token address widened to `bytes32`**; a token that is not a registered NAV asset simply reports nothing. Removing a token releases it but does **not** hand it back to the default adapter; re-include it with `includeAssetInDefaultAdapter`, or it is reported by nobody.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.kpk.io/funds/infrastructure/architecture/onchain-accounting/meta-balance-adapters/wallet-yield.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
