forked from mico/idle_moloch
91 lines
3.6 KiB
Solidity
91 lines
3.6 KiB
Solidity
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
pragma solidity >=0.5.0;
|
|
|
|
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
|
|
import '@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol';
|
|
|
|
library UniswapV2Library {
|
|
using LowGasSafeMath for uint256;
|
|
|
|
// 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);
|
|
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
|
|
require(token0 != address(0));
|
|
}
|
|
|
|
// 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(
|
|
uint256(
|
|
keccak256(
|
|
abi.encodePacked(
|
|
hex'ff',
|
|
factory,
|
|
keccak256(abi.encodePacked(token0, token1)),
|
|
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
// fetches and sorts the reserves for a pair
|
|
function getReserves(
|
|
address factory,
|
|
address tokenA,
|
|
address tokenB
|
|
) internal view returns (uint256 reserveA, uint256 reserveB) {
|
|
(address token0, ) = sortTokens(tokenA, tokenB);
|
|
(uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pairFor(factory, tokenA, tokenB)).getReserves();
|
|
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
|
|
}
|
|
|
|
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset
|
|
function getAmountOut(
|
|
uint256 amountIn,
|
|
uint256 reserveIn,
|
|
uint256 reserveOut
|
|
) internal pure returns (uint256 amountOut) {
|
|
require(amountIn > 0, 'INSUFFICIENT_INPUT_AMOUNT');
|
|
require(reserveIn > 0 && reserveOut > 0);
|
|
uint256 amountInWithFee = amountIn.mul(997);
|
|
uint256 numerator = amountInWithFee.mul(reserveOut);
|
|
uint256 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(
|
|
uint256 amountOut,
|
|
uint256 reserveIn,
|
|
uint256 reserveOut
|
|
) internal pure returns (uint256 amountIn) {
|
|
require(amountOut > 0, 'INSUFFICIENT_OUTPUT_AMOUNT');
|
|
require(reserveIn > 0 && reserveOut > 0);
|
|
uint256 numerator = reserveIn.mul(amountOut).mul(1000);
|
|
uint256 denominator = reserveOut.sub(amountOut).mul(997);
|
|
amountIn = (numerator / denominator).add(1);
|
|
}
|
|
|
|
// performs chained getAmountIn calculations on any number of pairs
|
|
function getAmountsIn(
|
|
address factory,
|
|
uint256 amountOut,
|
|
address[] memory path
|
|
) internal view returns (uint256[] memory amounts) {
|
|
require(path.length >= 2);
|
|
amounts = new uint256[](path.length);
|
|
amounts[amounts.length - 1] = amountOut;
|
|
for (uint256 i = path.length - 1; i > 0; i--) {
|
|
(uint256 reserveIn, uint256 reserveOut) = getReserves(factory, path[i - 1], path[i]);
|
|
amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut);
|
|
}
|
|
}
|
|
}
|