solidity – Addressing Confusions Regarding Uniswap’s Constant Formula

contract-developmentgo-ethereumliquidity-providersolidityuniswap

let's say Liquidity on ETH/DAI pair is 5 ETH and 18652 DAI. At the time of this writing, I figured out how many DAI is 5ETH and 18652 was the number.

So 1eth costs costs 3730DAI

Now, let's say user puts 2ETH into the contract to get a DAI in exchange.

x * y = k
5 * 18652 = 93260 (at start)

since 2 ETH get in, 93260 / 7 = 13332.8571.. and 
in the end, user gets 18652 - 13332.8571 = 5319 DAI

How is this possible ? it's unfair as 2 ETH should get him 2 * 3730 = 7460, but instead, uniswap gives him 5319.

Am I doing something wrong ? if you tell me that initial liquidity is not enough, I'd ask how ? 5 ETH seems to me a good starting point in any pool. No ?

I'd appreciate the nice explanation of what's going on here…

Best Answer

Yes, it's an issue of liquidity.

You can say that 5 ETH is a good starting point, but it's relative: in your example you're swapping 2 ETH - which is almost half the pool. So there is significant slippage occuring. After the swap there is much more ETH in the pool than before - ETH has become less valuable - so the user has received less DAI in return.

If we change your example so that the user doesn't swap 2 ETH but only 0.01 ETH (so 0.2% of the pool instead of 40%), the user would get 37.22 in return (see calculation below). As the original ETH price you calculated was 3730, you see he now get's a fair amount because he only swapped a small portion of the pool.

This is the function we can use to calculate how much the user can get for a trade:

    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
        require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
        require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
        uint amountInWithFee = amountIn.mul(997);
        uint numerator = amountInWithFee.mul(reserveOut);
        uint denominator = reserveIn.mul(1000).add(amountInWithFee);
        amountOut = numerator / denominator;
    }
Related Topic