1
0
forked from mico/idle_moloch
idle_moloch/lib/swap-router-contracts/contracts/V2SwapRouter.sol

95 lines
3.8 KiB
Solidity

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity =0.7.6;
pragma abicoder v2;
import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './interfaces/IV2SwapRouter.sol';
import './base/ImmutableState.sol';
import './base/PeripheryPaymentsWithFeeExtended.sol';
import './libraries/Constants.sol';
import './libraries/UniswapV2Library.sol';
/// @title Uniswap V2 Swap Router
/// @notice Router for stateless execution of swaps against Uniswap V2
abstract contract V2SwapRouter is IV2SwapRouter, ImmutableState, PeripheryPaymentsWithFeeExtended {
using LowGasSafeMath for uint256;
// supports fee-on-transfer tokens
// requires the initial amount to have already been sent to the first pair
function _swap(address[] memory path, address _to) private {
for (uint256 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(factoryV2, input, output));
uint256 amountInput;
uint256 amountOutput;
// scope to avoid stack too deep errors
{
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves();
(uint256 reserveInput, uint256 reserveOutput) =
input == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput);
amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput);
}
(uint256 amount0Out, uint256 amount1Out) =
input == token0 ? (uint256(0), amountOutput) : (amountOutput, uint256(0));
address to = i < path.length - 2 ? UniswapV2Library.pairFor(factoryV2, output, path[i + 2]) : _to;
pair.swap(amount0Out, amount1Out, to, new bytes(0));
}
}
/// @inheritdoc IV2SwapRouter
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to
) external payable override returns (uint256 amountOut) {
// use amountIn == Constants.CONTRACT_BALANCE as a flag to swap the entire balance of the contract
bool hasAlreadyPaid;
if (amountIn == Constants.CONTRACT_BALANCE) {
hasAlreadyPaid = true;
amountIn = IERC20(path[0]).balanceOf(address(this));
}
pay(
path[0],
hasAlreadyPaid ? address(this) : msg.sender,
UniswapV2Library.pairFor(factoryV2, path[0], path[1]),
amountIn
);
// find and replace to addresses
if (to == Constants.MSG_SENDER) to = msg.sender;
else if (to == Constants.ADDRESS_THIS) to = address(this);
uint256 balanceBefore = IERC20(path[path.length - 1]).balanceOf(to);
_swap(path, to);
amountOut = IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore);
require(amountOut >= amountOutMin, 'Too little received');
}
/// @inheritdoc IV2SwapRouter
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to
) external payable override returns (uint256 amountIn) {
amountIn = UniswapV2Library.getAmountsIn(factoryV2, amountOut, path)[0];
require(amountIn <= amountInMax, 'Too much requested');
pay(path[0], msg.sender, UniswapV2Library.pairFor(factoryV2, path[0], path[1]), amountIn);
// find and replace to addresses
if (to == Constants.MSG_SENDER) to = msg.sender;
else if (to == Constants.ADDRESS_THIS) to = address(this);
_swap(path, to);
}
}