AMM reserves: distinguish recorded reserves from token balances
An AMM’s recorded reserves and its token balances can differ. A direct token transfer can change balanceOf without immediately changing getReserves or issuing LP tokens. To explain the difference, reconstruct the pair’s state transitions rather than calling every balance increase new liquidity capital or fee revenue.
This guide examines the referenced Uniswap v2 pair implementation. It does not assume every AMM, clone or unusual token has identical behavior, and it does not recommend extracting a balance surplus.
Keep three objects in the worksheet
The first object is the pair’s recorded reserves for token0 and token1. The second is each token contract’s actual balanceOf result for the pair. The third is the LP-token ownership ledger, including total supply and any holder quantities relevant to the claim.
Read all three under an aligned state boundary. Comparing yesterday’s reserves with today’s token balance can create an apparent surplus that never existed at one point. For transaction-level attribution, whole-block snapshots may also contain intervening transfers or pair actions.
The v2 Pair source, getReserves, _update, skim and sync, provides the mechanism examined here. _update records balances as reserves. skim transfers the balance excess over recorded reserves, whereas sync updates reserves to the current balances. Neither function’s body performs an LP-share mint.
Save the exact source version inspected and match it to the deployment if making a real-project claim. The repository’s reference code supplies an example mechanism; its existence does not prove that an arbitrary same-named pool uses those bytes.
A hypothetical direct transfer
Assume ordinary tokens with exact transfers, no rebasing and no other state changes. Pair P starts with reserves of 100 token0 and 100 token1, matching actual balances. Its LP total supply is 10000 units. Holder H owns 1000, or 10% of that supply.
An external address transfers 10 token0 directly to P without calling mint. Immediately afterward, actual balances are 110 and 100, while recorded reserves remain 100 and 100. The LP total supply remains 10000; the sender has not acquired newly issued LP shares through that transfer.
| Field | Before direct transfer | Immediately afterward |
|---|---|---|
| Recorded reserve0 | 100 | 100 |
| Recorded reserve1 | 100 | 100 |
| Actual balance0 | 100 | 110 |
| Actual balance1 | 100 | 100 |
| Balance0 minus reserve0 | 0 | 10 |
| LP total supply | 10000 | 10000 |
| H’s LP fraction | 1000/10000 = 10% | 10% |
The unchanged ownership fraction does not settle the value or availability of every claim. It establishes that the assumed direct transfer did not itself issue the sender a new LP position. Identify the actual liquidity event before calling a token transfer an LP deposit.
Compare skim and sync as alternative paths
From the same post-transfer state, consider path A: a successful skim under the stipulated ordinary-token behavior moves the excess 10 token0 to its specified recipient. Actual balances return to 100 and 100. Recorded reserves remain 100 and 100, with no LP-share mint in that call.
In alternative path B, sync records current balances as reserves. Reserve0 becomes 110 and reserve1 stays 100. No excess is transferred by that function, and its own call does not issue LP shares. The ten units remain in the pair in this alternative history.
| Result from the common starting state | Skim path A | Sync path B |
|---|---|---|
| Actual balance0 | 100 | 110 |
| Recorded reserve0 | 100 | 110 |
| Actual balance1 and reserve1 | 100 | 100 |
| Excess moved to recipient | 10 token0 | 0 |
| LP shares minted by this call | 0 | 0 |
The paths are mutually alternative examples. Do not subtract ten through skim and also keep the same ten as a sync increase without an intervening movement. A chronological trace is necessary when several real calls occur.
Under path B, the recorded reserve product changes from 100 × 100 = 10000 to 110 × 100 = 11000, while no swap was stipulated. Therefore an increase in the reserve product is not by itself evidence of trading volume or fees paid by traders.
Check event meaning against state meaning
A token’s Transfer event records a token-specific movement. A pair’s Mint, Burn, Swap and Sync events describe different pair operations. Their names are leads, not interchangeable confirmations of one economic event.
Connect an LP-capital claim to minted shares and the corresponding asset movements. Connect a fee claim to the applicable mechanism and recipient. Do not label a direct transfer fee revenue simply because the pair’s assets increased.
The referenced source also contains separate protocol-fee logic associated with liquidity events. A later fee-minting result can depend on tracked state. The narrow observation that sync itself does not mint LP shares should not be expanded into a claim that the transferred quantity can never affect any later fee accounting.
Keep gross token movement, reserve update, share issuance and fee treatment as separate columns. Their timing differences are what the worksheet is designed to expose.
Different boundary: the actual balance falls below reserves
Consider a separate hypothetical token that changes balances through a negative rebase. P’s token0 balance falls from 100 to 90 while recorded reserve0 remains 100. There is now a deficit of ten, not a negative surplus available to distribute.
In the referenced skim calculation, subtracting a larger reserve from a smaller balance uses checked subtraction and can revert. Do not interpret a failed skim as evidence that no reserve mismatch exists. Inspect both balances and the actual call result.
If a valid sync subsequently records the 90 balance, the reserve update reflects the balance change. It is not evidence of a trade selling ten units. Rebase mechanics require their own token evidence, while the pair worksheet explains how that behavior reaches recorded reserves.
Transfer behavior can invalidate simple arithmetic
A transfer-tax token can cause the recipient to receive less than the requested excess. Some tokens have special zero-transfer behavior or other conditions. Read the actual transfer implementation and reconcile pre- and post-balances rather than assuming a successful call means ordinary one-for-one receipts.
For example, a nominal ten-unit surplus transfer with a stipulated 10% recipient-side tax could deliver nine units under that specific token model. Do not carry that result into another token or infer the tax solely from a balance gap. Fees, rebases, missing transactions and unit errors need separate tests.
Likewise, a modified pair may expose different functions, permission checks or reserve rules. The v2 source is not a universal classification system for every balance mismatch visible in an analytics dashboard.
A later fee event needs its own calculation
For a separate raw-unit example, assume reserves were originally 1000000 of each token, LP supply was 1000000 and tracked kLast was 10^12. A direct transfer and sync leave reserves at 1100000 and 1000000 while kLast remains the stipulated old value. Assume the referenced fee switch is on and a later liquidity operation completes successfully.
At its _mintFee step, the integer square roots are 1048808 for the current reserve product and 1000000 for kLast. The source’s formula gives floor(1000000 × 48808 / (5 × 1048808 + 1000000)) = floor(48808000000/6244040) = 7816 protocol LP units at that step. The rest of the successful operation has its own share and asset accounting.
This is an assumed state-transition calculation, not a measured live event. If the enclosing operation reverts, an intermediate mint does not become final. More importantly, the computed fee-mint quantity does not prove that traders generated the reserve growth: the example stipulated a direct transfer. Keep mechanism and origin separate.
For the different recipient-tax model, a nominal transfer of ten can reduce the pair by ten, increase the recipient by nine and assign one to the specified tax treatment. Verify all three destinations or deductions rather than forcing nine received to equal ten sent.
A Sync event alone does not prove that the explicit sync function was called. In the reference code it is emitted by _update, which other pair operations also use. Preserve the surrounding call and other events before naming the operation that caused the reserve update.
A practical reconciliation checklist
| Action | Retain | Misreading prevented |
|---|---|---|
| Fix pair identity | Network, token order, code and cutoff | Applying reference behavior to a different deployment |
| Read both ledgers | getReserves and token balanceOf at aligned state | Treating one as a substitute for the other |
| Observe share ownership | LP total supply and actual issuance | Calling every transfer contributed LP capital |
| Reconstruct the path | Direct transfers and subsequent pair calls | Counting alternative skim/sync outcomes together |
| Verify recipients | Actual amounts received and token behavior | Assuming nominal transfer equals net receipt |
| Classify economic effect | Asset, reserve, ownership and fee columns | Converting a reserve-product increase into volume |
Revisit after a reserve update, unusual-token event, corrected transaction boundary or deployment-code clarification. Release the balance-reserve difference with its explanation and unresolved amount. The result is an auditable state bridge, not a claim that a visible excess belongs to any particular observer or proves organic liquidity growth.
FAQ
Does sending tokens directly to a pair automatically mint LP shares?
Not in the referenced mechanism. Verify the actual mint operation and resulting share ledger rather than inferring ownership from a transfer.
Does sync transfer the difference to a recipient?
In this reference implementation, it updates reserves to balances. The separate skim function has the surplus-transfer role under its applicable conditions.