github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/test/contracts/uniswap/v2/UniswapV2Router01.sol (about) 1 pragma solidity =0.6.6; 2 3 import './IUniswapV2Factory.sol'; 4 import './TransferHelper.sol'; 5 6 import './UniswapV2Library.sol'; 7 import './IUniswapV2Router01.sol'; 8 import './IERC20.sol'; 9 import './IWETH.sol'; 10 11 contract UniswapV2Router01 is IUniswapV2Router01 { 12 address public immutable override factory; 13 address public immutable override WETH; 14 15 modifier ensure(uint deadline) { 16 require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED'); 17 _; 18 } 19 20 constructor(address _factory, address _WETH) public { 21 factory = _factory; 22 WETH = _WETH; 23 } 24 25 receive() external payable { 26 assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract 27 } 28 29 // **** ADD LIQUIDITY **** 30 function _addLiquidity( 31 address tokenA, 32 address tokenB, 33 uint amountADesired, 34 uint amountBDesired, 35 uint amountAMin, 36 uint amountBMin 37 ) private returns (uint amountA, uint amountB) { 38 // create the pair if it doesn't exist yet 39 if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) { 40 IUniswapV2Factory(factory).createPair(tokenA, tokenB); 41 } 42 (uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB); 43 if (reserveA == 0 && reserveB == 0) { 44 (amountA, amountB) = (amountADesired, amountBDesired); 45 } else { 46 uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB); 47 if (amountBOptimal <= amountBDesired) { 48 require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); 49 (amountA, amountB) = (amountADesired, amountBOptimal); 50 } else { 51 uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA); 52 assert(amountAOptimal <= amountADesired); 53 require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); 54 (amountA, amountB) = (amountAOptimal, amountBDesired); 55 } 56 } 57 } 58 function addLiquidity( 59 address tokenA, 60 address tokenB, 61 uint amountADesired, 62 uint amountBDesired, 63 uint amountAMin, 64 uint amountBMin, 65 address to, 66 uint deadline 67 ) external override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) { 68 (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin); 69 address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); 70 TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); 71 TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); 72 liquidity = IUniswapV2Pair(pair).mint(to); 73 } 74 function addLiquidityETH( 75 address token, 76 uint amountTokenDesired, 77 uint amountTokenMin, 78 uint amountETHMin, 79 address to, 80 uint deadline 81 ) external override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) { 82 (amountToken, amountETH) = _addLiquidity( 83 token, 84 WETH, 85 amountTokenDesired, 86 msg.value, 87 amountTokenMin, 88 amountETHMin 89 ); 90 address pair = UniswapV2Library.pairFor(factory, token, WETH); 91 TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken); 92 IWETH(WETH).deposit{value: amountETH}(); 93 assert(IWETH(WETH).transfer(pair, amountETH)); 94 liquidity = IUniswapV2Pair(pair).mint(to); 95 if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); // refund dust eth, if any 96 } 97 98 // **** REMOVE LIQUIDITY **** 99 function removeLiquidity( 100 address tokenA, 101 address tokenB, 102 uint liquidity, 103 uint amountAMin, 104 uint amountBMin, 105 address to, 106 uint deadline 107 ) public override ensure(deadline) returns (uint amountA, uint amountB) { 108 address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); 109 IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair 110 (uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to); 111 (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); 112 (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); 113 require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); 114 require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); 115 } 116 function removeLiquidityETH( 117 address token, 118 uint liquidity, 119 uint amountTokenMin, 120 uint amountETHMin, 121 address to, 122 uint deadline 123 ) public override ensure(deadline) returns (uint amountToken, uint amountETH) { 124 (amountToken, amountETH) = removeLiquidity( 125 token, 126 WETH, 127 liquidity, 128 amountTokenMin, 129 amountETHMin, 130 address(this), 131 deadline 132 ); 133 TransferHelper.safeTransfer(token, to, amountToken); 134 IWETH(WETH).withdraw(amountETH); 135 TransferHelper.safeTransferETH(to, amountETH); 136 } 137 function removeLiquidityWithPermit( 138 address tokenA, 139 address tokenB, 140 uint liquidity, 141 uint amountAMin, 142 uint amountBMin, 143 address to, 144 uint deadline, 145 bool approveMax, uint8 v, bytes32 r, bytes32 s 146 ) external override returns (uint amountA, uint amountB) { 147 address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); 148 uint value = approveMax ? uint(-1) : liquidity; 149 IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); 150 (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); 151 } 152 function removeLiquidityETHWithPermit( 153 address token, 154 uint liquidity, 155 uint amountTokenMin, 156 uint amountETHMin, 157 address to, 158 uint deadline, 159 bool approveMax, uint8 v, bytes32 r, bytes32 s 160 ) external override returns (uint amountToken, uint amountETH) { 161 address pair = UniswapV2Library.pairFor(factory, token, WETH); 162 uint value = approveMax ? uint(-1) : liquidity; 163 IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); 164 (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline); 165 } 166 167 // **** SWAP **** 168 // requires the initial amount to have already been sent to the first pair 169 function _swap(uint[] memory amounts, address[] memory path, address _to) private { 170 for (uint i; i < path.length - 1; i++) { 171 (address input, address output) = (path[i], path[i + 1]); 172 (address token0,) = UniswapV2Library.sortTokens(input, output); 173 uint amountOut = amounts[i + 1]; 174 (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); 175 address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to; 176 IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(amount0Out, amount1Out, to, new bytes(0)); 177 } 178 } 179 function swapExactTokensForTokens( 180 uint amountIn, 181 uint amountOutMin, 182 address[] calldata path, 183 address to, 184 uint deadline 185 ) external override ensure(deadline) returns (uint[] memory amounts) { 186 amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); 187 require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); 188 TransferHelper.safeTransferFrom(path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]); 189 _swap(amounts, path, to); 190 } 191 function swapTokensForExactTokens( 192 uint amountOut, 193 uint amountInMax, 194 address[] calldata path, 195 address to, 196 uint deadline 197 ) external override ensure(deadline) returns (uint[] memory amounts) { 198 amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); 199 require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); 200 TransferHelper.safeTransferFrom(path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]); 201 _swap(amounts, path, to); 202 } 203 function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) 204 external 205 override 206 payable 207 ensure(deadline) 208 returns (uint[] memory amounts) 209 { 210 require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); 211 amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path); 212 require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); 213 IWETH(WETH).deposit{value: amounts[0]}(); 214 assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); 215 _swap(amounts, path, to); 216 } 217 function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) 218 external 219 override 220 ensure(deadline) 221 returns (uint[] memory amounts) 222 { 223 require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); 224 amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); 225 require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); 226 TransferHelper.safeTransferFrom(path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]); 227 _swap(amounts, path, address(this)); 228 IWETH(WETH).withdraw(amounts[amounts.length - 1]); 229 TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); 230 } 231 function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) 232 external 233 override 234 ensure(deadline) 235 returns (uint[] memory amounts) 236 { 237 require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH'); 238 amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); 239 require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); 240 TransferHelper.safeTransferFrom(path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]); 241 _swap(amounts, path, address(this)); 242 IWETH(WETH).withdraw(amounts[amounts.length - 1]); 243 TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); 244 } 245 function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) 246 external 247 override 248 payable 249 ensure(deadline) 250 returns (uint[] memory amounts) 251 { 252 require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); 253 amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); 254 require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); 255 IWETH(WETH).deposit{value: amounts[0]}(); 256 assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); 257 _swap(amounts, path, to); 258 if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); // refund dust eth, if any 259 } 260 261 function quote(uint amountA, uint reserveA, uint reserveB) public pure override returns (uint amountB) { 262 return UniswapV2Library.quote(amountA, reserveA, reserveB); 263 } 264 265 function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure override returns (uint amountOut) { 266 return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); 267 } 268 269 function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) public pure override returns (uint amountIn) { 270 return UniswapV2Library.getAmountOut(amountOut, reserveIn, reserveOut); 271 } 272 273 function getAmountsOut(uint amountIn, address[] memory path) public view override returns (uint[] memory amounts) { 274 return UniswapV2Library.getAmountsOut(factory, amountIn, path); 275 } 276 277 function getAmountsIn(uint amountOut, address[] memory path) public view override returns (uint[] memory amounts) { 278 return UniswapV2Library.getAmountsIn(factory, amountOut, path); 279 } 280 }