I have the next code to get familiar with uniswap mechanics:
- create pair contract
- get reserves
- invoke
getAmountsOutand provide all UNI token reserves
const pairAddress = await _V2Factory.getPair(uniToken, wethToken);
const pairContract = new ethers.Contract(
pairAddress,
IUniswapV2Pair.abi,
_provider
);
const tmpReserves = await pairContract.getReserves();
const reserves = [reserves.reserve0, reserves.reserve1];
console.log("reserves", reserves);
const output = await router.getAmountsOut(reserves[0], [
uniToken.address,
wethToken.address,
]);
console.log("output", output);
Output is:
- reserves:
[ 36851089197799104779745113323n, 281312509765248795074n ] - output:
[ 36851089197799104779745113323n, 140444953548298972803n ]
The question is why I do not receive as the second element of output array equals to 281312509765248795074n - the full WETH liquidity in pair but just part of liquidity equals to 140444953548298972803n value?
I'm running local hardhat node and 3-rd parties actions should not affect the result. I tried on mainnet as well, obviously results are the same.
Tried also switch from getAmountsOut to getAmountOut, but it behaves the same way:
const output2 = await router.getAmountOut(
reserves[0],
reserves[0],
reserves[1]
);
console.log("output2", output2);
output: 143271499822164119007n
Uniswap and other constant product automated market makers (AMM) use the following invariant for each pool:
Where
xandyare the amounts of the tokens in the pool andkis a constant.The function
getAmountsOutsimulates a trade in the pool. After any trade,xandychanges, but the invariant still holds:If you call
getAmountsOutwithxas the parameter, you essentially ask (ignoring the swap fees for a moment) "how muchywould I get if I doubledxin the pool?" Thenx' = 2xand the invariant is:Solving it for
y'you gety' = y / 2balances in the pool. The expected output from this trade isy - y', which is again equal toy / 2and approximately matches your output. Incidentally, this trade would also push up the price in the pool 4 times, since price is defined asy/x.In the real code, the result is slightly different, since:
xbefore the trade is made.