github.com/cwntr/go-defi@v0.0.0-20210629134751-07f9ec2f7e66/contracts/handlers/sushiswap/libraries/UniswapV2Library.sol (about)

     1  pragma solidity >=0.5.0;
     2  
     3  import "@openzeppelin/contracts/math/SafeMath.sol";
     4  import "../IUniswapV2Pair.sol";
     5  
     6  
     7  library UniswapV2Library {
     8      using SafeMath for uint256;
     9  
    10      // returns sorted token addresses, used to handle return values from pairs sorted in this order
    11      function sortTokens(address tokenA, address tokenB)
    12          internal
    13          pure
    14          returns (address token0, address token1)
    15      {
    16          require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES");
    17          (token0, token1) = tokenA < tokenB
    18              ? (tokenA, tokenB)
    19              : (tokenB, tokenA);
    20          require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS");
    21      }
    22  
    23      // calculates the CREATE2 address for a pair without making any external calls
    24      function pairFor(
    25          address factory,
    26          address tokenA,
    27          address tokenB
    28      ) internal pure returns (address pair) {
    29          (address token0, address token1) = sortTokens(tokenA, tokenB);
    30  
    31          pair = address(
    32              uint256(
    33                  keccak256(
    34                      abi.encodePacked(
    35                          hex"ff",
    36                          factory,
    37                          keccak256(abi.encodePacked(token0, token1)),
    38                          hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash
    39                      )
    40                  )
    41              )
    42          );
    43      }
    44  
    45      // fetches and sorts the reserves for a pair
    46      function getReserves(
    47          address factory,
    48          address tokenA,
    49          address tokenB
    50      ) internal view returns (uint256 reserveA, uint256 reserveB) {
    51          (address token0, ) = sortTokens(tokenA, tokenB);
    52          (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(
    53              pairFor(factory, tokenA, tokenB)
    54          )
    55              .getReserves();
    56          (reserveA, reserveB) = tokenA == token0
    57              ? (reserve0, reserve1)
    58              : (reserve1, reserve0);
    59      }
    60  
    61      // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset
    62      function quote(
    63          uint256 amountA,
    64          uint256 reserveA,
    65          uint256 reserveB
    66      ) internal pure returns (uint256 amountB) {
    67          require(amountA > 0, "UniswapV2Library: INSUFFICIENT_AMOUNT");
    68          require(
    69              reserveA > 0 && reserveB > 0,
    70              "UniswapV2Library: INSUFFICIENT_LIQUIDITY"
    71          );
    72          amountB = amountA.mul(reserveB) / reserveA;
    73      }
    74  
    75      // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
    76      function getAmountOut(
    77          uint256 amountIn,
    78          uint256 reserveIn,
    79          uint256 reserveOut
    80      ) internal pure returns (uint256 amountOut) {
    81          require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT");
    82          require(
    83              reserveIn > 0 && reserveOut > 0,
    84              "UniswapV2Library: INSUFFICIENT_LIQUIDITY"
    85          );
    86          uint256 amountInWithFee = amountIn.mul(997);
    87          uint256 numerator = amountInWithFee.mul(reserveOut);
    88          uint256 denominator = reserveIn.mul(1000).add(amountInWithFee);
    89          amountOut = numerator / denominator;
    90      }
    91  
    92      // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    93      function getAmountIn(
    94          uint256 amountOut,
    95          uint256 reserveIn,
    96          uint256 reserveOut
    97      ) internal pure returns (uint256 amountIn) {
    98          require(amountOut > 0, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT");
    99          require(
   100              reserveIn > 0 && reserveOut > 0,
   101              "UniswapV2Library: INSUFFICIENT_LIQUIDITY"
   102          );
   103          uint256 numerator = reserveIn.mul(amountOut).mul(1000);
   104          uint256 denominator = reserveOut.sub(amountOut).mul(997);
   105          amountIn = (numerator / denominator).add(1);
   106      }
   107  
   108      // performs chained getAmountOut calculations on any number of pairs
   109      function getAmountsOut(
   110          address factory,
   111          uint256 amountIn,
   112          address[] memory path
   113      ) internal view returns (uint256[] memory amounts) {
   114          require(path.length >= 2, "UniswapV2Library: INVALID_PATH");
   115          amounts = new uint256[](path.length);
   116          amounts[0] = amountIn;
   117          for (uint256 i; i < path.length - 1; i++) {
   118              (uint256 reserveIn, uint256 reserveOut) = getReserves(
   119                  factory,
   120                  path[i],
   121                  path[i + 1]
   122              );
   123              amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
   124          }
   125      }
   126  
   127      // performs chained getAmountIn calculations on any number of pairs
   128      function getAmountsIn(
   129          address factory,
   130          uint256 amountOut,
   131          address[] memory path
   132      ) internal view returns (uint256[] memory amounts) {
   133          require(path.length >= 2, "UniswapV2Library: INVALID_PATH");
   134          amounts = new uint256[](path.length);
   135          amounts[amounts.length - 1] = amountOut;
   136          for (uint256 i = path.length - 1; i > 0; i--) {
   137              (uint256 reserveIn, uint256 reserveOut) = getReserves(
   138                  factory,
   139                  path[i - 1],
   140                  path[i]
   141              );
   142              amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
   143          }
   144      }
   145  }