> 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/onchain-accounting/meta-balance-adapters/fluid-vaults.md).

# Fluid Vaults

One immutable meta-adapter that reports an account's collateral and debt across any Fluid T1 vault. Per vault it emits a `Collateral` leg (supply) and a `Borrowed` leg (debt), aggregated over the account's Fluid NFT positions in that vault.

* **Type:** Meta-adapter
* **protocolSubId:** `keccak256("fluid-vaults")`
* **Instance key:** the Fluid T1 vault address, widened to `bytes32`.
* **Source:** [`FluidVaultsMetaBalanceAdapter.sol`](https://github.com/karpatkey/onchain-accounting/blob/main/src/balances/MetaBalanceAdapters/FluidVaultsMetaBalanceAdapter.sol)

{% hint style="warning" %}
Only Fluid **T1** vaults are supported — Smart vaults (T2/T3/T4) have a different, longer `constantsView` layout. This is **enforced on-chain**, not merely by convention: the token read is gated on the VaultResolver's `getVaultType(vault)` and fails closed, so a mis-configured non-T1 instance reads back as no tokens and reports nothing — no legs, no underlying assets. The guard matters because adding an instance is a `MANAGER` config transaction rather than a deploy, and non-T1 vaults are the majority of those live on mainnet.
{% endhint %}

***

## Positions returned

Up to two legs per vault:

| Leg        | PositionKind | isDebt  | Description                                            |
| ---------- | ------------ | ------- | ------------------------------------------------------ |
| Collateral | `Collateral` | `false` | Total supplied collateral, in the vault's supply token |
| Borrow     | `Borrowed`   | `true`  | Total outstanding debt, in the vault's borrow token    |

A leg is dropped when its amount is zero, when the token is not registered in NAVCalculator, or when filtered out by `assetFilter`. If the account **has debt** in the vault and the borrow token is unregistered, the vault reports **nothing at all** — the collateral leg included — rather than emitting collateral with no offsetting debt, which would over-report NAV.

The NFT aggregation is likewise **complete or nothing**: if a position read runs out of gas mid-loop, the vault raises `FluidPositionGasExhausted(vault, nftId, stipend, consumed)` rather than returning the partial sum. Each NFT contributes both a supply and a borrow, so silently omitting one moves equity by `supply − borrow` — which is an *over*-report for an underwater position, not merely a conservative under-report. Making the truncation visible is the only answer that is safe in both directions. See [Never report collateral without its debt](/funds/infrastructure/onchain-accounting/balance-adapters.md#how-an-adapter-is-built).

***

## Balance calculation

<figure><img src="/files/VApX5s6rAoaJ9dj2ZoHA" alt="Flowchart of the Fluid Vaults balance adapter: read calls derive position legs into PositionBalance entries."><figcaption><p>Fluid Vaults adapter — how the underlying balances reported to the NAV Calculator are derived.</p></figcaption></figure>

The supply/borrow tokens come from the vault's `constantsView()` (`supplyToken`, `borrowToken`). Amounts are aggregated across the account's Fluid NFT positions via the VaultResolver (logic in `FluidVaultLib`):

```
nftIds = VaultResolver.positionsNftIdOfUser(account)
for each nftId where VaultResolver.vaultByNftId(nftId) == vault:
    pos = VaultResolver.positionByNftId(nftId)
    if pos.isLiquidated: skip
    collateral += pos.supply
    debt       += pos.borrow
```

`collateral` is reported in supply-token decimals, `debt` in borrow-token decimals. Liquidated positions are skipped.

***

## Identity

* **positionId:** `abi.encode(address vault)`
* **positionKind:** `Collateral` (supply leg), `Borrowed` (debt leg)

There is no `labels` field on the position. The adapter implements `positionLabels(positionId)`, which returns `["Vault", "<collateral>/<debt> #<vaultId>"]` — e.g. `["Vault", "wstETH/USDC #4"]` — surfaced only by the verbose reads (`getAccountPositionsVerbose` / `getAccountNavVerbose`); the full breadcrumb is `[protocolName, ...labels]`.

A Fluid vault is **not** an ERC20 — `name()`, `symbol()` and `version()` all revert on it — so the leaf is built from the vault's token pair, exactly as the Morpho markets adapter does. Fluid's own per-vault id is appended because **the pair alone is not unique**: mainnet carries many more live T1 vaults than distinct pairs, and every configured vault has a live same-pair twin, so labelling by pair alone would reproduce the indistinguishability the leaf exists to remove. Symbols resolve from the NAV's registered-asset record — which maps the ERC-7528 native sentinel to the chain's native symbol, since several T1 vaults use it as one side — falling back to a direct ERC20 read and then to `"?"`, so an unreadable side renders as `"?/USDC"`.

***

## Constructor

```solidity
constructor(address vaultResolver_, address navCalculator_)
```

| Parameter        | Description                                                                                                       |
| ---------------- | ----------------------------------------------------------------------------------------------------------------- |
| `vaultResolver_` | Fluid VaultResolver address (chain-level constant) used for NFT enumeration and per-NFT reads. Must be a contract |
| `navCalculator_` | NAVCalculator address, used for the registered-asset registry. Must be a contract                                 |

***

## Registration

Register the adapter with `addMetaBalanceAdapter(adapter, instances)`, then add or remove vaults with `addMetaInstances(adapter, instances)` / `removeMetaInstances(adapter, instances)`. The instance coordinate is the T1 vault address widened to `bytes32`.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kpk.io/funds/infrastructure/onchain-accounting/meta-balance-adapters/fluid-vaults.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
