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.
Last updated
Reports an account's wallet-held (unstaked) Curve LP position across any configured pool, decomposed pro-rata into the pool's underlying coins.
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 adapter.
Type: Meta-adapter
protocolSubId: keccak256("curve-pools")
Instance key: the pool address, widened to bytes32.
Source: CurvePoolsMetaBalanceAdapter.sol
One leg per registered pool coin with a non-zero wallet share:
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.
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.
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 and Convex 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 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.
With `walletLp = lpToken.balanceOf(account)` and `totalSupply` (ERC20 `totalSupply()`, falling back to the StableSwap-NG `total_supply()` storage variant), each coin amount is:
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.
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].
navCalculator_
NAVCalculator address (must be a contract); source of the asset registry and the instance set
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.
Last updated
amount[i] = poolBalance[i] * walletLp / totalSupplyconstructor(address navCalculator_)