> 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/uniswap-v2.md).

# Uniswap V2

The Uniswap V2 adapter reports an account's V2 LP across any pair as the dilution-adjusted pro-rata share of both reserves, emitted as one `Supplied` leg per token. A single immutable meta-adapter serves every pair; the active pair set lives on NAVCalculator.

* **Type:** Meta-adapter
* **protocolSubId:** `keccak256("uniswap-v2")`
* **Instance key:** the Uniswap V2 pair address, widened to bytes32.
* **Source:** [`UniswapV2PoolsMetaBalanceAdapter.sol`](https://github.com/karpatkey/onchain-accounting/blob/main/src/balances/MetaBalanceAdapters/uniswap/UniswapV2PoolsMetaBalanceAdapter.sol)

***

## Positions returned

Per pair instance, up to two legs:

| Leg          | PositionKind | isDebt  | Description                          |
| ------------ | ------------ | ------- | ------------------------------------ |
| token0 share | `Supplied`   | `false` | Account's pro-rata share of reserve0 |
| token1 share | `Supplied`   | `false` | Account's pro-rata share of reserve1 |

Legs with zero amount, unregistered assets, or assets excluded by `assetFilter` are dropped.

***

## Balance calculation

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

Delegated to `UniswapV2PairLib.pairAmounts(pair, account)`. The account's LP balance is converted to underlying reserves against an **effective** supply that includes the protocol fee LP the pair would mint on its next mint/burn — so the reported amounts match what an LP would actually receive on `burn`:

```
balance         = pair.balanceOf(account)
totalSupply     = pair.totalSupply()
(r0, r1)        = pair.getReserves()
effectiveSupply = totalSupply + pendingProtocolMint        // V2 _mintFee dilution

amount0 = balance × r0 / effectiveSupply
amount1 = balance × r1 / effectiveSupply
```

The dilution term mirrors V2's internal `_mintFee`, the LP the pair would mint to `feeTo` on the next burn:

```
pendingProtocolMint = totalSupply × (√k − √kLast) × numFactor / (rootKCoeff·√k + rootKLastCoeff·√kLast)
```

The three coefficients `(numFactor, rootKCoeff, rootKLastCoeff)` come from a virtual `_mintFeeConstants()` hook, so byte-compatible forks can override them. Uniswap V2 (and SushiSwap, which shares them) use `(1, 5, 1)` — i.e. `(√k − √kLast) / (5·√k + √kLast)`, capturing 1/6 of fee growth.

It is 0 when `feeTo` is unset, `kLast == 0`, or `√k <= √kLast`. `feeTo()` and `kLast()` are read defensively, so forks omitting them are treated as having no protocol fee.

{% hint style="info" %}
**An absent `feeTo()` and a malformed one are treated differently**, because this is the one defensive read whose failure direction is **upward**: dropping the dilution term shrinks `effectiveSupply` and so *raises* the reported share. A read that **fails** means a fork without protocol fees, and reporting undiluted is correct — that is why the defensive read exists. A read that **succeeds** but returns a word that is not a valid address means a malformed factory: the dilution is unknowable, so the pair is **dropped** rather than valued on a guess. Treating the second case as "no protocol fee" over-reports the position.
{% endhint %}

***

## Identity

* **positionId:** `abi.encode(address pair)` — one positionId per pair instance.
* **positionKind:** `Supplied` for both legs.

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

***

## Constructor

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

| Parameter        | Description                                      |
| ---------------- | ------------------------------------------------ |
| `navCalculator_` | NAVCalculator contract for asset-registry access |

No protocol addresses are pinned — every pair is self-describing (`token0`, `token1`, `factory`, reserves are read from the pair itself).

***

## Registration

Register the adapter once with `addMetaBalanceAdapter`, then enable each pair with `addMetaInstances`. The instance coordinate is the Uniswap V2 pair address widened to bytes32. The adapter holds no instance state — it reads its active set from `NAV_CALCULATOR.getMetaInstances(address(this))`.


---

# 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/uniswap-v2.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.
