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 }