6

Context: We are creating a smart contract which integrates Uniswap DEX for swapping Tokens to ETH. We need to make sure one swap does not impact the token price more than 3%.

We are in need to write a function which takes in input the price_impact: uint, reserve0: uint and reserve1: uint and outputs the maximum amount of tokens which when swapped for ETH on uniswap will have the given price impact on the token price.

So, can someone please help in understanding how is the price impact calculated on the uniswap swap page, and also in writing a function which ouputs maximum number of tokens to be swapped for ETH which would have the given price impact?


Exchange: https://uniswap.org

Docs: https://uniswap.org/docs/v2

Pricing Docs: https://uniswap.org/docs/v2/javascript-SDK/pricing

Glossary: https://uniswap.org/docs/v2/protocol-overview/glossary/#docs-header

1
  • Do you want the solution in solidity or javascript (since your are linking to the js SDK) ? You need to fetch reserve for the pair, then solve the equation which would imo look like something like this reserveB - getAmountOut(x) = reserveB B*0.97 whereas reserveB = token reserve. getAmountOut : github.com/Uniswap/uniswap-v2-periphery/blob/master/contracts/…
    – Xavier59
    Nov 11, 2020 at 23:46

1 Answer 1

3

Late to the question, but since it's still unanswered I'll write a solution; it should help people still struggling with UniswapV2 math.

So, the price impact is usually defined as the relative variation of price due to a swap. If the price initially was pi and finally pf, the price impact will be PI = (pf-pi)/pi.

By price we are considering the nominal price (no fees), which is the ratio between the reserves, so:

enter image description here

with in and out indicating the reserves of input and output tokens respectively.

The final reserves are given by:

enter image description here

enter image description here

with x_in the input amount, and x_out the output amount, which can be given by the following formula (taken from uniswap's code):

enter image description here

Putting all the formulas together we can take x_in as a function of the price impact and the initial reserves:

enter image description here

with:

enter image description here

Writing it all in solidity this is how it looks:

pragma solidity ^0.8.0;

// https://github.com/Uniswap/v2-core/blob/v1.0.1/contracts/libraries/Math.sol
import '/path/to/Math.sol';

// https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol
import '/path/to/UniswapV2Library.sol';

contract UniswapV2Helper {
    address private constant UniV2Factory = ...;
    address private constant WETH = ...;
    
    uint256 private constant PRICE_IMPACT_DECIMALS = 18;  // for integer math
    
    // @notice Get max amount of tokens without impacting the price more than maxPriceImpact
    //         Swap output is WETH
    // @param tokenIn Address of ERC20 to swap
    // @param maxPriceImpact Price impact with 'PRICE_IMPACT_DECIMALS' decimals
    function getMaxAmountIn(address tokenIn, uint256 maxPriceImpact) public returns(uint256) {
        require(maxPriceImpact < 10**PRICE_IMPACT_DECIMALS, "maxPriceImpact too many decimals");
        
        // get reserves
        (uint256 reserveIn, /*uint256 reserveOut*/) = UniswapV2Library.getReserves(UniV2Factory, tokenIn, WETH);
        
        return _getMaxAmountIn(reserveIn, maxPriceImpact);
    }
    
    function _getMaxAmountIn(uint256 R, uint256 maxPriceImpact) public pure returns(uint256) {
        uint256 p = 10**(PRICE_IMPACT_DECIMALS*2)/(maxPriceImpact + 10**PRICE_IMPACT_DECIMALS);
        
        uint256 temp = 9*p*p + 4*1000*997*p*(10**PRICE_IMPACT_DECIMALS);
        uint256 sqrt = Math.sqrt(temp);
        
        return (sqrt - 1997*p)*R/(2*997*p);
    }
}

Hopefully I didn't make some math mistakes. Hope it helps someone!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.