pragma solidity =0.6.6; | |
interface IUniswapV2Factory { | |
event PairCreated(address indexed token0, address indexed token1, address pair, uint); | |
function getPair(address tokenQ, address tokenW) external view returns (address pair); | |
function allPairs(uint) external view returns (address pair); | |
function allPairsLength() external view returns (uint); | |
function createPair(address tokenQ, address tokenW) external returns (address pair); | |
function setRouter(address) external; | |
function claim(address, address, address) external; | |
function redirectInterestStream(address, address, address) external; | |
function setLiquidityToken(address, address) external; | |
} | |
interface IUniswapV2Pair { | |
event Approval(address indexed owner, address indexed spender, uint value); | |
event Transfer(address indexed from, address indexed to, uint value); | |
function name() external pure returns (string memory); | |
function symbol() external pure returns (string memory); | |
function decimals() external pure returns (uint8); | |
function totalSupply() external view returns (uint); | |
function balanceOf(address owner) external view returns (uint); | |
function allowance(address owner, address spender) external view returns (uint); | |
function approve(address spender, uint value) external returns (bool); | |
function transfer(address to, uint value) external returns (bool); | |
function transferFrom(address from, address to, uint value) external returns (bool); | |
function DOMAIN_SEPARATOR() external view returns (bytes32); | |
function PERMIT_TYPEHASH() external pure returns (bytes32); | |
function nonces(address owner) external view returns (uint); | |
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; | |
event Mint(address indexed sender, uint amount0, uint amount1); | |
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); | |
event Swap( | |
address indexed sender, | |
uint amount0In, | |
uint amount1In, | |
uint amount0Out, | |
uint amount1Out, | |
address indexed to | |
); | |
event Sync(uint112 reserve0, uint112 reserve1); | |
function MINIMUM_LIQUIDITY() external pure returns (uint); | |
function factory() external view returns (address); | |
function token0() external view returns (address); | |
function token1() external view returns (address); | |
function liquidityToken() external view returns (address); | |
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); | |
function price0CumulativeLast() external view returns (uint); | |
function price1CumulativeLast() external view returns (uint); | |
function kLast() external view returns (uint); | |
function mint(address to) external returns (uint liquidity); | |
function burn(address to) external returns (uint amount0, uint amount1); | |
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; | |
function skim(address to) external; | |
function sync() external; | |
function initialize(address, address) external; | |
function setLiquidityToken(address) external; | |
function redirectInterestStream(address, address) external; | |
function claim(address, address) external; | |
} | |
interface IUniswapV2Router01 { | |
function factory() external pure returns (address); | |
function redirectInterestStream( | |
address pair, | |
address token | |
) external; | |
function claim( | |
address pair, | |
address token | |
) external; | |
function addLiquidity( | |
address tokenA, | |
address tokenB, | |
uint amountADesired, | |
uint amountBDesired, | |
uint amountAMin, | |
uint amountBMin, | |
address to, | |
uint deadline | |
) external returns (uint amountA, uint amountB, uint liquidity); | |
function addLiquidityImbalanced( | |
address tokenA, | |
address tokenB, | |
uint amountA, | |
uint amountB, | |
address to, | |
uint deadline | |
) external returns (uint, uint, uint); | |
function removeLiquidity( | |
address tokenA, | |
address tokenB, | |
uint liquidity, | |
uint amountAMin, | |
uint amountBMin, | |
address to, | |
uint deadline | |
) external returns (uint amountA, uint amountB); | |
function removeLiquidityWithPermit( | |
address tokenA, | |
address tokenB, | |
uint liquidity, | |
uint amountAMin, | |
uint amountBMin, | |
address to, | |
uint deadline, | |
bool approveMax, uint8 v, bytes32 r, bytes32 s | |
) external returns (uint amountA, uint amountB); | |
function swapExactTokensForTokens( | |
uint amountIn, | |
uint amountOutMin, | |
address[] calldata path, | |
address to, | |
uint deadline | |
) external returns (uint[] memory amounts); | |
function swapTokensForExactTokens( | |
uint amountOut, | |
uint amountInMax, | |
address[] calldata path, | |
address to, | |
uint deadline | |
) external returns (uint[] memory amounts); | |
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); | |
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); | |
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); | |
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); | |
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); | |
} | |
interface IUniswapV2Router02 is IUniswapV2Router01 { | |
function swapExactTokensForTokensSupportingFeeOnTransferTokens( | |
uint amountIn, | |
uint amountOutMin, | |
address[] calldata path, | |
address to, | |
uint deadline | |
) external; | |
} | |
interface IERC20 { | |
event Approval(address indexed owner, address indexed spender, uint value); | |
event Transfer(address indexed from, address indexed to, uint value); | |
function name() external view returns (string memory); | |
function symbol() external view returns (string memory); | |
function decimals() external view returns (uint8); | |
function totalSupply() external view returns (uint); | |
function balanceOf(address owner) external view returns (uint); | |
function allowance(address owner, address spender) external view returns (uint); | |
function approve(address spender, uint value) external returns (bool); | |
function transfer(address to, uint value) external returns (bool); | |
function transferFrom(address from, address to, uint value) external returns (bool); | |
} | |
contract UniswapYieldV2Router02 is IUniswapV2Router02 { | |
using SafeMath for uint; | |
address public immutable override factory; | |
address public amm; | |
modifier ensure(uint deadline) { | |
require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED'); | |
_; | |
} | |
constructor(address _factory) public { | |
factory = _factory; | |
amm = msg.sender; | |
} | |
receive() external payable { | |
assert(msg.sender == address(0)); | |
} | |
function setRouter(address _router) external { | |
require(msg.sender == amm, 'UniswapV2Router: FORBIDDEN'); | |
IUniswapV2Factory(factory).setRouter(_router); | |
} | |
function setAMM(address _amm) external { | |
require(msg.sender == amm, "UniswapV2Router: FORBIDDEN"); | |
amm = _amm; | |
} | |
function redirectInterestStream( | |
address pair, | |
address token | |
) external virtual override { | |
IUniswapV2Factory(factory).redirectInterestStream(pair, token, amm); | |
} | |
function claim( | |
address pair, | |
address token | |
) external virtual override { | |
IUniswapV2Factory(factory).claim(pair, token, amm); | |
} | |
// **** ADD LIQUIDITY **** | |
function _addLiquidity( | |
address tokenA, | |
address tokenB, | |
uint amountADesired, | |
uint amountBDesired, | |
uint amountAMin, | |
uint amountBMin | |
) internal virtual returns (uint amountA, uint amountB) { | |
require(msg.sender == amm, "UniswapV2Router: FORBIDDEN"); | |
// create the pair if it doesn't exist yet | |
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) { | |
IUniswapV2Factory(factory).createPair(tokenA, tokenB); | |
} | |
(uint reserveA, uint reserveB) = UniswapV2Library.getReserves(factory, tokenA, tokenB); | |
if (reserveA == 0 && reserveB == 0) { | |
(amountA, amountB) = (amountADesired, amountBDesired); | |
} else { | |
uint amountBOptimal = UniswapV2Library.quote(amountADesired, reserveA, reserveB); | |
if (amountBOptimal <= amountBDesired) { | |
require(amountBOptimal >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); | |
(amountA, amountB) = (amountADesired, amountBOptimal); | |
} else { | |
uint amountAOptimal = UniswapV2Library.quote(amountBDesired, reserveB, reserveA); | |
assert(amountAOptimal <= amountADesired); | |
require(amountAOptimal >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); | |
(amountA, amountB) = (amountAOptimal, amountBDesired); | |
} | |
} | |
} | |
function addLiquidityImbalanced( | |
address tokenA, | |
address tokenB, | |
uint amountA, | |
uint amountB, | |
address to, | |
uint deadline | |
) external virtual override ensure(deadline) returns (uint, uint, uint) { | |
require(msg.sender == amm, "UniswapV2Router: FORBIDDEN"); | |
// create the pair if it doesn't exist yet | |
if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) { | |
IUniswapV2Factory(factory).createPair(tokenA, tokenB); | |
} | |
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); | |
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); | |
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); | |
return (amountA, amountB, IUniswapV2Pair(pair).mint(to)); | |
} | |
function addLiquidity( | |
address tokenA, | |
address tokenB, | |
uint amountADesired, | |
uint amountBDesired, | |
uint amountAMin, | |
uint amountBMin, | |
address to, | |
uint deadline | |
) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) { | |
(amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin); | |
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); | |
TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); | |
TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); | |
liquidity = IUniswapV2Pair(pair).mint(to); | |
} | |
// **** REMOVE LIQUIDITY **** | |
function removeLiquidity( | |
address tokenA, | |
address tokenB, | |
uint liquidity, | |
uint amountAMin, | |
uint amountBMin, | |
address to, | |
uint deadline | |
) public virtual override ensure(deadline) returns (uint amountA, uint amountB) { | |
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); | |
IUniswapV2Pair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair | |
(uint amount0, uint amount1) = IUniswapV2Pair(pair).burn(to); | |
(address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); | |
(amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); | |
require(amountA >= amountAMin, 'UniswapV2Router: INSUFFICIENT_A_AMOUNT'); | |
require(amountB >= amountBMin, 'UniswapV2Router: INSUFFICIENT_B_AMOUNT'); | |
} | |
function removeLiquidityWithPermit( | |
address tokenA, | |
address tokenB, | |
uint liquidity, | |
uint amountAMin, | |
uint amountBMin, | |
address to, | |
uint deadline, | |
bool approveMax, uint8 v, bytes32 r, bytes32 s | |
) external virtual override returns (uint amountA, uint amountB) { | |
address pair = UniswapV2Library.pairFor(factory, tokenA, tokenB); | |
uint value = approveMax ? uint(-1) : liquidity; | |
IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); | |
(amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); | |
} | |
// **** SWAP **** | |
// 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 { | |
for (uint i; i < path.length - 1; i++) { | |
(address input, address output) = (path[i], path[i + 1]); | |
(address token0,) = UniswapV2Library.sortTokens(input, output); | |
uint amountOut = amounts[i + 1]; | |
(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; | |
IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output)).swap( | |
amount0Out, amount1Out, to, new bytes(0) | |
); | |
} | |
} | |
function swapExactTokensForTokens( | |
uint amountIn, | |
uint amountOutMin, | |
address[] calldata path, | |
address to, | |
uint deadline | |
) external virtual override ensure(deadline) returns (uint[] memory amounts) { | |
amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path); | |
require(amounts[amounts.length - 1] >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); | |
TransferHelper.safeTransferFrom( | |
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0] | |
); | |
_swap(amounts, path, to); | |
} | |
function swapTokensForExactTokens( | |
uint amountOut, | |
uint amountInMax, | |
address[] calldata path, | |
address to, | |
uint deadline | |
) external virtual override ensure(deadline) returns (uint[] memory amounts) { | |
amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); | |
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); | |
} | |
// **** 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( | |
uint amountIn, | |
uint amountOutMin, | |
address[] calldata path, | |
address to, | |
uint deadline | |
) external virtual override ensure(deadline) { | |
TransferHelper.safeTransferFrom( | |
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amountIn | |
); | |
uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); | |
_swapSupportingFeeOnTransferTokens(path, to); | |
require( | |
IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, | |
'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT' | |
); | |
} | |
// **** LIBRARY FUNCTIONS **** | |
function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) { | |
return UniswapV2Library.quote(amountA, reserveA, reserveB); | |
} | |
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) | |
public | |
pure | |
virtual | |
override | |
returns (uint amountOut) | |
{ | |
return UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); | |
} | |
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) | |
public | |
pure | |
virtual | |
override | |
returns (uint amountIn) | |
{ | |
return UniswapV2Library.getAmountIn(amountOut, reserveIn, reserveOut); | |
} | |
function getAmountsOut(uint amountIn, address[] memory path) | |
public | |
view | |
virtual | |
override | |
returns (uint[] memory amounts) | |
{ | |
return UniswapV2Library.getAmountsOut(factory, amountIn, path); | |
} | |
function getAmountsIn(uint amountOut, address[] memory path) | |
public | |
view | |
virtual | |
override | |
returns (uint[] memory amounts) | |
{ | |
return UniswapV2Library.getAmountsIn(factory, amountOut, path); | |
} | |
} | |
// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) | |
library SafeMath { | |
function add(uint x, uint y) internal pure returns (uint z) { | |
require((z = x + y) >= x, 'ds-math-add-overflow'); | |
} | |
function sub(uint x, uint y) internal pure returns (uint z) { | |
require((z = x - y) <= x, 'ds-math-sub-underflow'); | |
} | |
function mul(uint x, uint y) internal pure returns (uint z) { | |
require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); | |
} | |
} | |
library UniswapV2Library { | |
using SafeMath for uint; | |
// returns sorted token addresses, used to handle return values from pairs sorted in this order | |
function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { | |
require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); | |
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); | |
require(token0 != address(0), 'UniswapV2Library: ZERO_ADDRESS'); | |
} | |
// calculates the CREATE2 address for a pair without making any external calls | |
function pairFor(address factory, address tokenA, address tokenB) internal pure returns (address pair) { | |
(address token0, address token1) = sortTokens(tokenA, tokenB); | |
pair = address(uint(keccak256(abi.encodePacked( | |
hex'ff', | |
factory, | |
keccak256(abi.encodePacked(token0, token1)), | |
hex'8e978531212bcc589ea0f0289172831260e33616e69dd7e97c80f169438af63c' // init code hash | |
)))); | |
} | |
// fetches and sorts the reserves for a pair | |
function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { | |
(address token0,) = sortTokens(tokenA, tokenB); | |
(uint reserve0, uint reserve1,) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves(); | |
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); | |
} | |
// given some amount of an asset and pair reserves, returns an equivalent amount of the other asset | |
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) { | |
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); | |
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); | |
amountB = amountA.mul(reserveB) / reserveA; | |
} | |
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset | |
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { | |
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); | |
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); | |
uint amountInWithFee = amountIn.mul(997); | |
uint numerator = amountInWithFee.mul(reserveOut); | |
uint denominator = reserveIn.mul(1000).add(amountInWithFee); | |
amountOut = numerator / denominator; | |
} | |
// given an output amount of an asset and pair reserves, returns a required input amount of the other asset | |
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) { | |
require(amountOut > 0, 'UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT'); | |
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); | |
uint numerator = reserveIn.mul(amountOut).mul(1000); | |
uint denominator = reserveOut.sub(amountOut).mul(997); | |
amountIn = (numerator / denominator).add(1); | |
} | |
// performs chained getAmountOut calculations on any number of pairs | |
function getAmountsOut(address factory, uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) { | |
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); | |
amounts = new uint; | |
amounts[0] = amountIn; | |
for (uint i; i < path.length - 1; i++) { | |
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i], path[i + 1]); | |
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); | |
} | |
} | |
// performs chained getAmountIn calculations on any number of pairs | |
function getAmountsIn(address factory, uint amountOut, address[] memory path) internal view returns (uint[] memory amounts) { | |
require(path.length >= 2, 'UniswapV2Library: INVALID_PATH'); | |
amounts = new uint; | |
amounts[amounts.length - 1] = amountOut; | |
for (uint i = path.length - 1; i > 0; i--) { | |
(uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); | |
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); | |
} | |
} | |
} | |
// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false | |
library TransferHelper { | |
function safeApprove(address token, address to, uint value) internal { | |
// bytes4(keccak256(bytes('approve(address,uint256)'))); | |
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); | |
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); | |
} | |
function safeTransfer(address token, address to, uint value) internal { | |
// bytes4(keccak256(bytes('transfer(address,uint256)'))); | |
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); | |
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); | |
} | |
function safeTransferFrom(address token, address from, address to, uint value) internal { | |
// bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); | |
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); | |
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); | |
} | |
function safeTransferETH(address to, uint value) internal { | |
(bool success,) = to.call{value:value}(new bytes(0)); | |
require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); | |
} | |
} |
-
Notifications
You must be signed in to change notification settings - Fork 0
Yfiq/YFIQSWAP
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published