router

Created Diff never expires
138 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
446 lines
327 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
623 lines
pragma solidity =0.6.6;
pragma solidity ^0.6.0;


import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';
import '@uniswap/lib/contracts/libraries/TransferHelper.sol';


import './interfaces/IUniswapV2Router02.sol';
import '../interfaces/IUniswapV2Router02.sol';
import './libraries/UniswapV2Library.sol';
import '../libraries/UniswapV2Library2.sol';
import './libraries/SafeMath.sol';
import '../interfaces/IERC20WithFee.sol';
import './interfaces/IERC20.sol';
import '@uniswap/v2-periphery/contracts/interfaces/IWETH.sol';
import './interfaces/IWETH.sol';


contract UniswapV2Router02 is IUniswapV2Router02 {
contract UniswapV2Router03 is IUniswapV2Router02 {
using SafeMath for uint;
using SafeMath for uint;


address public immutable override factory;
address public immutable override factory;
address public immutable override WETH;
address public immutable override WETH;


modifier ensure(uint deadline) {
modifier ensure(uint deadline) {
require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED');
_;
_;
}
}


constructor(address _factory, address _WETH) public {
constructor(address _factory, address _WETH) public {
factory = _factory;
factory = _factory;
WETH = _WETH;
WETH = _WETH;
}
}


receive() external payable {
receive() external payable {
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract
}
}


// **** ADD LIQUIDITY ****
// **** ADD LIQUIDITY ****
function _addLiquidity(
function _addLiquidity(
address tokenA,
address tokenA,
address tokenB,
address tokenB,
uint amountADesired,
uint amountADesired,
uint amountBDesired,
uint amountBDesired,
uint amountAMin,
uint amountAMin,
uint amountBMin
uint amountBMin
) internal virtual returns (uint amountA, uint amountB) {
) internal virtual returns (uint amountA, uint amountB) {
// create the pair if it doesn't exist yet
// create the pair if it doesn't exist yet
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
IUniswapV2Factory(factory).createPair(tokenA, tokenB);
}
}
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
} else {
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
(amountA, amountB) = (amountADesired, amountBOptimal);
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
} else {
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA);
assert(amountAOptimal <= amountADesired);
assert(amountAOptimal <= amountADesired);
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
(amountA, amountB) = (amountAOptimal, amountBDesired);
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
}
}
}
}

function addLiquidity(
function addLiquidity(
address tokenA,
address tokenA,
address tokenB,
address tokenB,
uint amountADesired,
uint amountADesired,
uint amountBDesired,
uint amountBDesired,
uint amountAMin,
uint amountAMin,
uint amountBMin,
uint amountBMin,
address to,
address to,
uint deadline
uint deadline
Text moved from lines 385-389
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) {
)
external
virtual
override
ensure(deadline)
returns (
uint amountA,
uint amountB,
uint liquidity
)
{
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB);
liquidity = IUniswapV2Pair(pair).mint(to);
liquidity = IUniswapV2Pair(pair).mint(to);
}
}

function addLiquidityETH(
function addLiquidityETH(
address token,
address token,
uint amountTokenDesired,
uint amountTokenDesired,
uint amountTokenMin,
uint amountTokenMin,
uint amountETHMin,
uint amountETHMin,
address to,
address to,
uint deadline
uint deadline
Text moved from lines 361-366
) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) {
)
external
virtual
override
payable
ensure(deadline)
returns (
uint amountToken,
uint amountETH,
uint liquidity
)
{
(amountToken, amountETH) = _addLiquidity(
(amountToken, amountETH) = _addLiquidity(
token,
token,
WETH,
WETH,
amountTokenDesired,
amountTokenDesired,
msg.value,
msg.value,
amountTokenMin,
amountTokenMin,
amountETHMin
amountETHMin
);
);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
IWETH(WETH).deposit{value: amountETH}();
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IUniswapV2Pair(pair).mint(to);
liquidity = IUniswapV2Pair(pair).mint(to);
// refund dust eth, if any
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}
}


// **** ADD LIQUIDITY (supporting fee-on-transfer tokens) ****

function addLiquiditySupportingFeeOnTransferTokens(
address[2] calldata tokens,
uint[2] calldata desiredAmounts,
uint[2] calldata minAmounts,
bool[2] calldata isFOTTokenFlags,
address to,
uint deadline
)
external
ensure(deadline)
returns (
uint amountA,
uint amountB,
uint liquidity
)
{
(amountA, amountB) = _addLiquidity(
tokens[0],
tokens[1],
desiredAmounts[0],
desiredAmounts[1],
minAmounts[0],
minAmounts[1]
);
address pair = UniswapV2Library.pairFor(factory, tokens[0], tokens[1]);
if (isFOTTokenFlags[0]) {
IERC20WithFee(tokens[0]).transferExactDestFrom(msg.sender, pair, amountA);
} else {
TransferHelper.safeTransferFrom(tokens[0], msg.sender, pair, amountA);
}
if (isFOTTokenFlags[1]) {
IERC20WithFee(tokens[1]).transferExactDestFrom(msg.sender, pair, amountB);
} else {
TransferHelper.safeTransferFrom(tokens[1], msg.sender, pair, amountB);
}
liquidity = IUniswapV2Pair(pair).mint(to);
}

function addLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
bool isFOTToken,
address to,
uint deadline
)
external
payable
ensure(deadline)
returns (
uint amountToken,
uint amountETH,
uint liquidity
)
{
(amountToken, amountETH) = _addLiquidity(
token,
WETH,
amountTokenDesired,
msg.value,
amountTokenMin,
amountETHMin
);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
if (isFOTToken) {
IERC20WithFee(token).transferExactDestFrom(msg.sender, pair, amountToken);
} else {
TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken);
}
IWETH(WETH).deposit{value: amountETH}();
assert(IWETH(WETH).transfer(pair, amountETH));
liquidity = IUniswapV2Pair(pair).mint(to);
// refund dust eth, if any
if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH);
}

// **** REMOVE LIQUIDITY ****
// **** REMOVE LIQUIDITY ****
function removeLiquidity(
function removeLiquidity(
address tokenA,
address tokenA,
address tokenB,
address tokenB,
uint liquidity,
uint liquidity,
uint amountAMin,
uint amountAMin,
uint amountBMin,
uint amountBMin,
address to,
address to,
uint deadline
uint deadline
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to);
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB);
(address token0, ) = UniswapV2Library.sortTokens(tokenA, tokenB);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0);
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT');
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT');
}
}

function removeLiquidityETH(
function removeLiquidityETH(
address token,
address token,
uint liquidity,
uint liquidity,
uint amountTokenMin,
uint amountTokenMin,
uint amountETHMin,
uint amountETHMin,
address to,
address to,
uint deadline
uint deadline
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) {
(amountToken, amountETH) = removeLiquidity(
(amountToken, amountETH) = removeLiquidity(
token,
token,
WETH,
WETH,
liquidity,
liquidity,
amountTokenMin,
amountTokenMin,
amountETHMin,
amountETHMin,
address(this),
address(this),
deadline
deadline
);
);
TransferHelper.safeTransfer(token, to, amountToken);
TransferHelper.safeTransfer(token, to, amountToken);
IWETH(WETH).withdraw(amountETH);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
}

function removeLiquidityWithPermit(
function removeLiquidityWithPermit(
address tokenA,
address tokenA,
address tokenB,
address tokenB,
uint liquidity,
uint liquidity,
uint amountAMin,
uint amountAMin,
uint amountBMin,
uint amountBMin,
address to,
address to,
uint deadline,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override returns (uint amountA, uint amountB) {
) external virtual override returns (uint amountA, uint amountB) {
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB);
uint value = approveMax ? uint(-1) : liquidity;
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline);
}
}

function removeLiquidityETHWithPermit(
function removeLiquidityETHWithPermit(
address token,
address token,
uint liquidity,
uint liquidity,
uint amountTokenMin,
uint amountTokenMin,
uint amountETHMin,
uint amountETHMin,
address to,
address to,
uint deadline,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override returns (uint amountToken, uint amountETH) {
) external virtual override returns (uint amountToken, uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
(amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline);
}
}


// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
// **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) ****
function removeLiquidityETHSupportingFeeOnTransferTokens(
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
address token,
uint liquidity,
uint liquidity,
uint amountTokenMin,
uint amountTokenMin,
uint amountETHMin,
uint amountETHMin,
address to,
address to,
uint deadline
uint deadline
) public virtual override ensure(deadline) returns (uint amountETH) {
) public virtual override ensure(deadline) returns (uint amountETH) {
(, amountETH) = removeLiquidity(
(, amountETH) = removeLiquidity(token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline);
token,
Text moved with changes to lines 312-317 (92.7% similarity)
WETH,
liquidity,
amountTokenMin,
amountETHMin,
address(this),
deadline
);
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this)));
IWETH(WETH).withdraw(amountETH);
IWETH(WETH).withdraw(amountETH);
TransferHelper.safeTransferETH(to, amountETH);
TransferHelper.safeTransferETH(to, amountETH);
}
}

function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
address token,
uint liquidity,
uint liquidity,
uint amountTokenMin,
uint amountTokenMin,
uint amountETHMin,
uint amountETHMin,
address to,
address to,
uint deadline,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external virtual override returns (uint amountETH) {
) external virtual override returns (uint amountETH) {
address pair = UniswapV2Library.pairFor(factory, token, WETH);
address pair = UniswapV2Library.pairFor(factory, token, WETH);
uint value = approveMax ? uint(-1) : liquidity;
uint value = approveMax ? uint(-1) : liquidity;
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s);
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(
Text moved with changes from lines 182-187 (92.7% similarity)
token, liquidity, amountTokenMin, amountETHMin, to, deadline
token,
liquidity,
amountTokenMin,
amountETHMin,
to,
deadline
);
);
}
}


// **** SWAP ****
// **** SWAP ****
// requires the initial amount to have already been sent to the first pair
// requires the initial amount to have already been sent to the first pair
function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual {
function _swap(
uint[] memory amounts,
address[] memory path,
address _to
) internal virtual {
for (uint i; i < path.length - 1; i++) {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
(address token0, ) = UniswapV2Library.sortTokens(input, output);
uint amountOut = amounts[i + 1];
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap(
amount0Out, amount1Out, to, new bytes(0)
amount0Out,
amount1Out,
to,
new bytes(0)
);
);
}
}
}
}

function swapExactTokensForTokens(
function swapExactTokensForTokens(
uint amountIn,
uint amountIn,
uint amountOutMin,
uint amountOutMin,
address[] calldata path,
address[] calldata path,
address to,
address to,
uint deadline
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
path[0],
msg.sender,
UniswapV2Library.pairFor(factory, path[0], path[1]),
amounts[0]
);
);
_swap(amounts, path, to);
_swap(amounts, path, to);
}
}

function swapTokensForExactTokens(
function swapTokensForExactTokens(
uint amountOut,
uint amountOut,
uint amountInMax,
uint amountInMax,
address[] calldata path,
address[] calldata path,
address to,
address to,
uint deadline
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
path[0],
msg.sender,
UniswapV2Library.pairFor(factory, path[0], path[1]),
amounts[0]
);
);
_swap(amounts, path, to);
_swap(amounts, path, to);
}
}
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)

external
function swapExactETHForTokens(
virtual
uint amountOutMin,
override
address[] calldata path,
payable
address to,
ensure(deadline)
uint deadline
returns (uint[] memory amounts)
) external virtual override payable ensure(deadline) returns (uint[] memory amounts) {
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
_swap(amounts, path, to);
}
}
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)

external
function swapTokensForExactETH(
virtual
uint amountOut,
override
uint amountInMax,
ensure(deadline)
address[] calldata path,
returns (uint[] memory amounts)
address to,
{
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
path[0],
msg.sender,
UniswapV2Library.pairFor(factory, path[0], path[1]),
amounts[0]
);
);
_swap(amounts, path, address(this));
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
}
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)

external
function swapExactTokensForETH(
virtual
uint amountIn,
override
uint amountOutMin,
ensure(deadline)
address[] calldata path,
returns (uint[] memory amounts)
address to,
{
uint deadline
) external virtual override ensure(deadline) returns (uint[] memory amounts) {
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
path[0],
msg.sender,
UniswapV2Library.pairFor(factory, path[0], path[1]),
amounts[0]
);
);
_swap(amounts, path, address(this));
_swap(amounts, path, address(this));
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
IWETH(WETH).withdraw(amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]);
}
}
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)

external
function swapETHForExactTokens(
virtual
uint amountOut,
override
address[] calldata path,
payable
address to,
ensure(deadline)
uint deadline
returns (uint[] memory amounts)
) external virtual override payable ensure(deadline) returns (uint[] memory amounts) {
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
require(amounts[0] <= msg.value, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
IWETH(WETH).deposit{value: amounts[0]}();
IWETH(WETH).deposit{value: amounts[0]}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]));
_swap(amounts, path, to);
_swap(amounts, path, to);
// refund dust eth, if any
// refund dust eth, if any
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
}


// **** SWAP (supporting fee-on-transfer tokens) ****
// **** SWAP (supporting fee-on-transfer tokens) ****
// requires the initial amount to have already been sent to the first pair

function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = UniswapV2Library.sortTokens(input, output);
IUniswapV2Pair pair = IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output));
uint amountInput;
uint amountOutput;
{ // scope to avoid stack too deep errors
(uint reserve0, uint reserve1,) = pair.getReserves();
(uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factory, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountIn,
uint amountOutMin,
uint amountOutMin,
address[] calldata path,
address[] calldata path,
address to,
address to,
bool[] calldata isFOTTokenFlags,
uint deadline
uint deadline
) external virtual override ensure(deadline) {
) external virtual override ensure(deadline) {
(uint[] memory amounts, uint actualAmountOut) = UniswapV2Library2.getAmountsOut(
factory,
amountIn,
path,
msg.sender,
to,
isFOTTokenFlags
);
require(actualAmountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
path[0],
);
msg.sender,
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
UniswapV2Library.pairFor(factory, path[0], path[1]),
_swapSupportingFeeOnTransferTokens(path, to);
amountIn
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
);
_swap(amounts, path, to);
}
}

function swapExactETHForTokensSupportingFeeOnTransferTokens(
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
uint amountOutMin,
address[] calldata path,
address[] calldata path,
address to,
address to,
bool[] calldata isFOTTokenFlags,
uint deadline
uint deadline
Text moved to lines 95-100
)
) external virtual override payable ensure(deadline) {
external
virtual
override
payable
ensure(deadline)
{
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH');
uint amountIn = msg.value;
uint amountIn = msg.value;
(uint[] memory amounts, uint actualAmountOut) = UniswapV2Library2.getAmountsOut(
factory,
amountIn,
path,
msg.sender,
to,
isFOTTokenFlags
);
require(actualAmountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');

IWETH(WETH).deposit{value: amountIn}();
IWETH(WETH).deposit{value: amountIn}();
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn));
assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn));
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swap(amounts, path, to);
_swapSupportingFeeOnTransferTokens(path, to);
require(
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin,
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'
);
}
}

function swapExactTokensForETHSupportingFeeOnTransferTokens(
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountIn,
uint amountOutMin,
uint amountOutMin,
address[] calldata path,
address[] calldata path,
address to,
address to,
bool[] calldata isFOTTokenFlags,
uint deadline
uint deadline
Text moved to lines 70-74
)
) external virtual override ensure(deadline) {
external
virtual
override
ensure(deadline)
{
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
require(path[path.length - 1] == WETH, 'UniswapV2Router: INVALID_PATH');
(uint[] memory amounts, uint actualAmountOut) = UniswapV2Library2.getAmountsOut(
factory,
amountIn,
path,
msg.sender,
to,
isFOTTokenFlags
);
require(actualAmountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferFrom(
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn
path[0],
msg.sender,
UniswapV2Library.pairFor(factory, path[0], path[1]),
amountIn
);
);
_swapSupportingFeeOnTransferTokens(path, address(this));
_swap(amounts, path, address(this));
uint amountOut = IERC20(WETH).balanceOf(address(this));
IWETH(WETH).withdraw(actualAmountOut);
require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT');
TransferHelper.safeTransferETH(to, actualAmountOut);
IWETH(WETH).withdraw(amountOut);
}
TransferHelper.safeTransferETH(to, amountOut);

function swapTokensForExactTokensSupportingFeeOnTransferTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
bool[] calldata isFOTTokenFlags,
uint deadline
) external virtual override ensure(deadline) {
uint[] memory amounts = UniswapV2Library2.getAmountsIn(
factory,
amountOut,
path,
msg.sender,
to,
isFOTTokenFlags
);
require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0],
msg.sender,
UniswapV2Library.pairFor(factory, path[0], path[1]),
amounts[0]
);
_swap(amounts, path, to);
}
}


// **** LIBRARY FUNCTIONS ****
// **** LIBRARY FUNCTIONS ****
function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {
function quote(
uint amountA,
uint reserveA,
uint reserveB
) public virtual override pure returns (uint amountB) {
return UniswapV2Library.quote(amountA, reserveA, reserveB);
return UniswapV2Library.quote(amountA, reserveA, reserveB);
}
}


function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut)
function getAmountOut(
public
uint amountIn,
pure
uint reserveIn,
virtual
uint reserveOut
override
) public virtual override pure returns (uint amountOut) {
returns (uint amountOut)
{
return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut);
}
}


function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut)
function getAmountIn(
public
uint amountOut,
pure
uint reserveIn,
virtual
uint reserveOut
override
) public virtual override pure returns (uint amountIn) {
returns (uint amountIn)
{
return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut);
}
}


function getAmountsOut(uint amountIn, address[] memory path)
function getAmountsOut(uint amountIn, address[] memory path)
public
public
view
virtual
virtual
override
override
view
returns (uint[] memory amounts)
returns (uint[] memory amounts)
{
{
return UniswapV2Library.getAmountsOut(factory, amountIn, path);
return UniswapV2Library.getAmountsOut(factory, amountIn, path);
}
}


function getAmountsIn(uint amountOut, address[] memory path)
function getAmountsIn(uint amountOut, address[] memory path)
public
public
view
virtual
virtual
override
override
view
returns (uint[] memory amounts)
returns (uint[] memory amounts)
{
{
return UniswapV2Library.getAmountsIn(factory, amountOut, path);
return UniswapV2Library.getAmountsIn(factory, amountOut, path);
}
}

function getAmountsOutSupportingFeeOnTransferTokens(
uint amountIn,
address[] memory path,
address from,
address to,
bool[] memory isFOTTokenFlags
) public virtual view returns (uint[] memory amounts, uint actualAmountOut) {
return UniswapV2Library2.getAmountsOut(factory, amountIn, path, from, to, isFOTTokenFlags);
}

function getAmountsInSupportingFeeOnTransferTokens(
uint amountOut,
address[] memory path,
address from,
address to,
bool[] memory isFOTTokenFlags
) public virtual view returns (uint[] memory amounts) {
return UniswapV2Library2.getAmountsIn(factory, amountOut, path, from, to, isFOTTokenFlags);
}
}
}