Explain why a Uniswap v2 reserve differs from the pair’s token balance

The pair stores reserve snapshots, while an ERC-20 maintains the actual balance of the pair address. A direct transfer can change the second number without updating the first.

Read reserves and balances at one block

Read token0, token1 and getReserves from the pair. Query each token’s balanceOf using the pair address at the same block. In the example a positive difference of ten base units exists for token0.

getReserves().reserve0 = 1000
balanceOf(pair) token0 = 1010
excess                 =   10

Inspect transfers and pair events around the first divergence. In the reference pair, sync updates stored reserves from balances; skim sends excess balances to its recipient without first increasing the stored reserves. Reconstruct which action actually occurred from receipts.

Keep reserve and custody series separate

A dashboard that replaces reserve history with balance history will treat an unprocessed donation as a reserve change. Rebasing or unusual token behavior can also cause differences. Use the actual pair implementation and token accounting before attributing the excess to a swap. github.com UniswapV2Pair.sol