github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/contracts/uniswap/v2/UniswapV2Router02.sol (about)

     1  pragma solidity =0.6.6;
     2  
     3  import './IUniswapV2Factory.sol';
     4  import './TransferHelper.sol';
     5  
     6  import './IUniswapV2Router02.sol';
     7  import './UniswapV2Library.sol';
     8  import './SafeMath.sol';
     9  import './IERC20.sol';
    10  import './IWETH.sol';
    11  
    12  contract UniswapV2Router02 is IUniswapV2Router02 {
    13      using SafeMath for uint;
    14  
    15      address public immutable override factory;
    16      address public immutable override WETH;
    17  
    18      modifier ensure(uint deadline) {
    19          require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
    20          _;
    21      }
    22  
    23      constructor(address _factory, address _WETH) public {
    24          factory = _factory;
    25          WETH = _WETH;
    26      }
    27  
    28      receive() external payable {
    29          assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
    30      }
    31  
    32      // **** ADD LIQUIDITY ****
    33      function _addLiquidity(
    34          address tokenA,
    35          address tokenB,
    36          uint amountADesired,
    37          uint amountBDesired,
    38          uint amountAMin,
    39          uint amountBMin
    40      ) internal virtual returns (uint amountA, uint amountB) {
    41          // create the pair if it doesn't exist yet
    42          if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
    43              IUniswapV2Factory(factory).createPair(tokenA, tokenB);
    44          }
    45          (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
    46          if (reserveA == 0 && reserveB == 0) {
    47              (amountA, amountB) = (amountADesired, amountBDesired);
    48          } else {
    49              uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
    50              if (amountBOptimal <= amountBDesired) {
    51                  require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
    52                  (amountA, amountB) = (amountADesired, amountBOptimal);
    53              } else {
    54                  uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
    55                  assert(amountAOptimal <= amountADesired);
    56                  require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
    57                  (amountA, amountB) = (amountAOptimal, amountBDesired);
    58              }
    59          }
    60      }
    61      
    62      function addLiquidity(
    63          address tokenA,
    64          address tokenB,
    65          uint amountADesired,
    66          uint amountBDesired,
    67          uint amountAMin,
    68          uint amountBMin,
    69          address to,
    70          uint deadline
    71      ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
    72          (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
    73          address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
    74          TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
    75          TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
    76          liquidity = IUniswapV2Pair(pair).mint(to);
    77      }
    78  
    79      function addLiquidityETH(
    80          address token,
    81          uint amountTokenDesired,
    82          uint amountTokenMin,
    83          uint amountETHMin,
    84          address to,
    85          uint deadline
    86      ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
    87          (amountToken, amountETH) = _addLiquidity(
    88              token,
    89              WETH,
    90              amountTokenDesired,
    91              msg.value,
    92              amountTokenMin,
    93              amountETHMin
    94          );
    95          address pair = UniswapV2Library.pairFor(factory, token, WETH);
    96          TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
    97          IWETH(WETH).deposit{value: amountETH}();
    98          assert(IWETH(WETH).transfer(pair, amountETH));
    99          liquidity = IUniswapV2Pair(pair).mint(to);
   100          // refund dust eth, if any
   101          if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
   102      }
   103  
   104      // **** REMOVE LIQUIDITY ****
   105      function removeLiquidity(
   106          address tokenA,
   107          address tokenB,
   108          uint liquidity,
   109          uint amountAMin,
   110          uint amountBMin,
   111          address to,
   112          uint deadline
   113      ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
   114          address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
   115          IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
   116          (uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
   117          (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
   118          (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
   119          require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
   120          require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
   121      }
   122      function removeLiquidityETH(
   123          address token,
   124          uint liquidity,
   125          uint amountTokenMin,
   126          uint amountETHMin,
   127          address to,
   128          uint deadline
   129      ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
   130          (amountToken, amountETH) = removeLiquidity(
   131              token,
   132              WETH,
   133              liquidity,
   134              amountTokenMin,
   135              amountETHMin,
   136              address(this),
   137              deadline
   138          );
   139          TransferHelper.safeTransfer(token, to, amountToken);
   140          IWETH(WETH).withdraw(amountETH);
   141          TransferHelper.safeTransferETH(to, amountETH);
   142      }
   143      function removeLiquidityWithPermit(
   144          address tokenA,
   145          address tokenB,
   146          uint liquidity,
   147          uint amountAMin,
   148          uint amountBMin,
   149          address to,
   150          uint deadline,
   151          bool approveMax, uint8 v, bytes32 r, bytes32 s
   152      ) external virtual override returns (uint amountA, uint amountB) {
   153          address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
   154          uint value = approveMax ? uint(-1) : liquidity;
   155          IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
   156          (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
   157      }
   158      function removeLiquidityETHWithPermit(
   159          address token,
   160          uint liquidity,
   161          uint amountTokenMin,
   162          uint amountETHMin,
   163          address to,
   164          uint deadline,
   165          bool approveMax, uint8 v, bytes32 r, bytes32 s
   166      ) external virtual override returns (uint amountToken, uint amountETH) {
   167          address pair = UniswapV2Library.pairFor(factory, token, WETH);
   168          uint value = approveMax ? uint(-1) : liquidity;
   169          IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
   170          (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
   171      }
   172  
   173      // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
   174      function removeLiquidityETHSupportingFeeOnTransferTokens(
   175          address token,
   176          uint liquidity,
   177          uint amountTokenMin,
   178          uint amountETHMin,
   179          address to,
   180          uint deadline
   181      ) public virtual override ensure(deadline) returns (uint amountETH) {
   182          (, amountETH) = removeLiquidity(
   183              token,
   184              WETH,
   185              liquidity,
   186              amountTokenMin,
   187              amountETHMin,
   188              address(this),
   189              deadline
   190          );
   191          TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
   192          IWETH(WETH).withdraw(amountETH);
   193          TransferHelper.safeTransferETH(to, amountETH);
   194      }
   195      function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
   196          address token,
   197          uint liquidity,
   198          uint amountTokenMin,
   199          uint amountETHMin,
   200          address to,
   201          uint deadline,
   202          bool approveMax, uint8 v, bytes32 r, bytes32 s
   203      ) external virtual override returns (uint amountETH) {
   204          address pair = UniswapV2Library.pairFor(factory, token, WETH);
   205          uint value = approveMax ? uint(-1) : liquidity;
   206          IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
   207          amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
   208              token, liquidity, amountTokenMin, amountETHMin, to, deadline
   209          );
   210      }
   211  
   212      // **** SWAP ****
   213      // requires the initial amount to have already been sent to the first pair
   214      function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
   215          for (uint i; i < path.length - 1; i++) {
   216              (address input, address output) = (path[i], path[i + 1]);
   217              (address token0,) = UniswapV2Library.sortTokens(input, output);
   218              uint amountOut = amounts[i + 1];
   219              (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
   220              address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
   221              IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
   222                  amount0Out, amount1Out, to, new bytes(0)
   223              );
   224          }
   225      }
   226      function swapExactTokensForTokens(
   227          uint amountIn,
   228          uint amountOutMin,
   229          address[] calldata path,
   230          address to,
   231          uint deadline
   232      ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
   233          amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
   234          require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
   235          TransferHelper.safeTransferFrom(
   236              path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
   237          );
   238          _swap(amounts, path, to);
   239      }
   240      function swapTokensForExactTokens(
   241          uint amountOut,
   242          uint amountInMax,
   243          address[] calldata path,
   244          address to,
   245          uint deadline
   246      ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
   247          amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
   248          require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
   249          TransferHelper.safeTransferFrom(
   250              path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
   251          );
   252          _swap(amounts, path, to);
   253      }
   254      function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
   255          external
   256          virtual
   257          override
   258          payable
   259          ensure(deadline)
   260          returns (uint[] memory amounts)
   261      {
   262          require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
   263          amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
   264          require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
   265          IWETH(WETH).deposit{value: amounts[0]}();
   266          assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
   267          _swap(amounts, path, to);
   268      }
   269      function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
   270          external
   271          virtual
   272          override
   273          ensure(deadline)
   274          returns (uint[] memory amounts)
   275      {
   276          require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
   277          amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
   278          require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
   279          TransferHelper.safeTransferFrom(
   280              path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
   281          );
   282          _swap(amounts, path, address(this));
   283          IWETH(WETH).withdraw(amounts[amounts.length - 1]);
   284          TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
   285      }
   286      function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
   287          external
   288          virtual
   289          override
   290          ensure(deadline)
   291          returns (uint[] memory amounts)
   292      {
   293          require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
   294          amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
   295          require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
   296          TransferHelper.safeTransferFrom(
   297              path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
   298          );
   299          _swap(amounts, path, address(this));
   300          IWETH(WETH).withdraw(amounts[amounts.length - 1]);
   301          TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
   302      }
   303      function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
   304          external
   305          virtual
   306          override
   307          payable
   308          ensure(deadline)
   309          returns (uint[] memory amounts)
   310      {
   311          require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
   312          amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
   313          require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
   314          IWETH(WETH).deposit{value: amounts[0]}();
   315          assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
   316          _swap(amounts, path, to);
   317          // refund dust eth, if any
   318          if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
   319      }
   320  
   321      // **** SWAP (supporting fee-on-transfer tokens) ****
   322      // requires the initial amount to have already been sent to the first pair
   323      function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
   324          for (uint i; i < path.length - 1; i++) {
   325              (address input, address output) = (path[i], path[i + 1]);
   326              (address token0,) = UniswapV2Library.sortTokens(input, output);
   327              IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output));
   328              uint amountInput;
   329              uint amountOutput;
   330              { // scope to avoid stack too deep errors
   331              (uint reserve0, uint reserve1,) = pair.getReserves();
   332              (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
   333              amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
   334              amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
   335              }
   336              (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
   337              address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
   338              pair.swap(amount0Out, amount1Out, to, new bytes(0));
   339          }
   340      }
   341      function swapExactTokensForTokensSupportingFeeOnTransferTokens(
   342          uint amountIn,
   343          uint amountOutMin,
   344          address[] calldata path,
   345          address to,
   346          uint deadline
   347      ) external virtual override ensure(deadline) {
   348          TransferHelper.safeTransferFrom(
   349              path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
   350          );
   351          uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
   352          _swapSupportingFeeOnTransferTokens(path, to);
   353          require(
   354              IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
   355              'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
   356          );
   357      }
   358      function swapExactETHForTokensSupportingFeeOnTransferTokens(
   359          uint amountOutMin,
   360          address[] calldata path,
   361          address to,
   362          uint deadline
   363      )
   364          external
   365          virtual
   366          override
   367          payable
   368          ensure(deadline)
   369      {
   370          require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
   371          uint amountIn = msg.value;
   372          IWETH(WETH).deposit{value: amountIn}();
   373          assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn));
   374          uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
   375          _swapSupportingFeeOnTransferTokens(path, to);
   376          require(
   377              IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
   378              'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
   379          );
   380      }
   381      function swapExactTokensForETHSupportingFeeOnTransferTokens(
   382          uint amountIn,
   383          uint amountOutMin,
   384          address[] calldata path,
   385          address to,
   386          uint deadline
   387      )
   388          external
   389          virtual
   390          override
   391          ensure(deadline)
   392      {
   393          require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
   394          TransferHelper.safeTransferFrom(
   395              path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
   396          );
   397          _swapSupportingFeeOnTransferTokens(path, address(this));
   398          uint amountOut = IERC20(WETH).balanceOf(address(this));
   399          require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
   400          IWETH(WETH).withdraw(amountOut);
   401          TransferHelper.safeTransferETH(to, amountOut);
   402      }
   403  
   404      // **** LIBRARY FUNCTIONS ****
   405      function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
   406          return UniswapV2Library.quote(amountA, reserveA, reserveB);
   407      }
   408  
   409      function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
   410          public
   411          pure
   412          virtual
   413          override
   414          returns (uint amountOut)
   415      {
   416          return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
   417      }
   418  
   419      function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
   420          public
   421          pure
   422          virtual
   423          override
   424          returns (uint amountIn)
   425      {
   426          return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
   427      }
   428  
   429      function getAmountsOut(uint amountIn, address[] memory path)
   430          public
   431          view
   432          virtual
   433          override
   434          returns (uint[] memory amounts)
   435      {
   436          return UniswapV2Library.getAmountsOut(factory, amountIn, path);
   437      }
   438  
   439      function getAmountsIn(uint amountOut, address[] memory path)
   440          public
   441          view
   442          virtual
   443          override
   444          returns (uint[] memory amounts)
   445      {
   446          return UniswapV2Library.getAmountsIn(factory, amountOut, path);
   447      }
   448  }