> 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/curve-pools.md).

# Curve Pools

Reports an account's **wallet-held (unstaked)** Curve LP position across any configured pool, decomposed pro-rata into the pool's underlying coins. Gauge-staked LP and rewards are the separate [Curve Gauges](/funds/infrastructure/onchain-accounting/meta-balance-adapters/curve-gauges.md) adapter.

* **Type:** Meta-adapter
* **protocolSubId:** `keccak256("curve-pools")`
* **Instance key:** the pool address, widened to bytes32.
* **Source:** [`CurvePoolsMetaBalanceAdapter.sol`](https://github.com/karpatkey/onchain-accounting/blob/main/src/balances/MetaBalanceAdapters/curve/CurvePoolsMetaBalanceAdapter.sol)

***

## Positions returned

One leg per registered pool coin with a non-zero wallet share:

| Leg    | PositionKind | isDebt  | Description                                                   |
| ------ | ------------ | ------- | ------------------------------------------------------------- |
| Supply | `Supplied`   | `false` | Pro-rata share of one pool coin, from the account's wallet LP |

Unregistered, zero-amount, and asset-filtered coins are skipped. For metapools, `coins()` enumerates only the meta-coins; base-pool coins are not recursed into (the base LP token has its own price feed). Lending pools report wrapped-token balances.

***

## Balance calculation

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

The LP token is resolved from the pool by `CurvePoolLib.getLpToken` — the pool itself for classic StableSwap / TriCryptoNG (self-LP), or a separate ERC20 via `lp_token()` for StableSwap-NG factory / TwoCryptoNG pools.

{% hint style="warning" %}
**Legacy StableSwap pools are not decomposed here, deliberately.** On the oldest generation (3pool, whose LP is the separate 3Crv) `lp_token()` reverts, so resolution falls through to "the pool is its own LP token" — which is false for these pools, and `balanceOf` on the pool itself reverts. Wallet-held LP for such a pool therefore reports **nothing**.

Unlike the [gauge](/funds/infrastructure/onchain-accounting/meta-balance-adapters/curve-gauges.md) and [Convex](/funds/infrastructure/onchain-accounting/meta-balance-adapters/convex.md) staking paths, this is **not** resolved through Curve's registry, and the gap is intentional. Resolving it would flip this adapter from emitting nothing to emitting full `Supplied` coin legs — which double-counts for any operator who worked around the under-report the obvious way, by registering the LP token as an asset so the [default adapter](/funds/infrastructure/onchain-accounting/balance-adapters/erc20-default.md) reports it. That would be an over-report, the one direction this family must never take, so the under-report is held until all three consumers can be changed together.
{% endhint %}

With \`walletLp = lpToken.balanceOf(account)\` and \`totalSupply\` (ERC20 \`totalSupply()\`, falling back to the StableSwap-NG \`total\_supply()\` storage variant), each coin amount is:

```
amount[i] = poolBalance[i] * walletLp / totalSupply
```

`poolBalance[i]` is read via `balances(uint256)`, falling back to `balances(int128)` for Vyper 0.1.x pools. Coin enumeration similarly tries `coins(uint256)` then `coins(int128)`, up to `MAX_COINS = 8`.

***

## Identity

* **positionId:** `abi.encode(address pool)`
* **positionKind:** `Supplied`

There is no `labels` field on the position. The adapter implements `positionLabels(positionId)`, which returns `["AMM Liquidity Pool", "TOKEN0/TOKEN1/…"]` from the on-chain coin symbols — surfaced only by the verbose reads (`getAccountPositionsVerbose` / `getAccountNavVerbose`); the full breadcrumb is `[protocolName, ...labels]`.

***

## Constructor

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

| Parameter        | Description                                                                                   |
| ---------------- | --------------------------------------------------------------------------------------------- |
| `navCalculator_` | NAVCalculator address (must be a contract); source of the asset registry and the instance set |

***

## Registration

Registered as a meta-adapter via `addMetaBalanceAdapter(adapter)`, then per-pool instances are added with `addMetaInstances`. Each instance coordinate is the pool 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/curve-pools.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.
