Contract Name:
IndexedUniswapRouterMinter
Contract Source Code:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;
import "./BNum.sol";
contract BMath is BNum {
function calcSingleInGivenPoolOut(
uint256 tokenBalanceIn,
uint256 tokenWeightIn,
uint256 poolSupply,
uint256 totalWeight,
uint256 poolAmountOut,
uint256 swapFee
) internal pure returns (uint256 tokenAmountIn) {
uint256 normalizedWeight = bdiv(tokenWeightIn, totalWeight);
uint256 newPoolSupply = badd(poolSupply, poolAmountOut);
uint256 poolRatio = bdiv(newPoolSupply, poolSupply);
//uint newBalTi = poolRatio^(1/weightTi) * balTi;
uint256 boo = bdiv(BONE, normalizedWeight);
uint256 tokenInRatio = bpow(poolRatio, boo);
uint256 newTokenBalanceIn = bmul(tokenInRatio, tokenBalanceIn);
uint256 tokenAmountInAfterFee = bsub(newTokenBalanceIn, tokenBalanceIn);
// Do reverse order of fees charged in joinswap_ExternAmountIn, this way
// ``` pAo == joinswap_ExternAmountIn(Ti, joinswap_PoolAmountOut(pAo, Ti)) ```
//uint tAi = tAiAfterFee / (1 - (1-weightTi) * swapFee) ;
uint256 zar = bmul(bsub(BONE, normalizedWeight), swapFee);
tokenAmountIn = bdiv(tokenAmountInAfterFee, bsub(BONE, zar));
return tokenAmountIn;
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;
contract BNum {
uint256 internal constant BONE = 1e18;
uint256 internal constant MIN_BPOW_BASE = 1 wei;
uint256 internal constant MAX_BPOW_BASE = (2 * BONE) - 1 wei;
uint256 internal constant BPOW_PRECISION = BONE / 10**10;
uint256 internal constant MIN_WEIGHT = BONE / 4;
function btoi(uint256 a) internal pure returns (uint256) {
return a / BONE;
}
function bfloor(uint256 a) internal pure returns (uint256) {
return btoi(a) * BONE;
}
function badd(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "ERR_ADD_OVERFLOW");
return c;
}
function bsub(uint256 a, uint256 b) internal pure returns (uint256) {
(uint256 c, bool flag) = bsubSign(a, b);
require(!flag, "ERR_SUB_UNDERFLOW");
return c;
}
function bsubSign(uint256 a, uint256 b)
internal
pure
returns (uint256, bool)
{
if (a >= b) {
return (a - b, false);
} else {
return (b - a, true);
}
}
function bmul(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c0 = a * b;
require(a == 0 || c0 / a == b, "ERR_MUL_OVERFLOW");
uint256 c1 = c0 + (BONE / 2);
require(c1 >= c0, "ERR_MUL_OVERFLOW");
uint256 c2 = c1 / BONE;
return c2;
}
function bdiv(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "ERR_DIV_ZERO");
uint256 c0 = a * BONE;
require(a == 0 || c0 / a == BONE, "ERR_DIV_INTERNAL"); // bmul overflow
uint256 c1 = c0 + (b / 2);
require(c1 >= c0, "ERR_DIV_INTERNAL"); // badd require
uint256 c2 = c1 / b;
return c2;
}
// DSMath.wpow
function bpowi(uint256 a, uint256 n) internal pure returns (uint256) {
uint256 z = n % 2 != 0 ? a : BONE;
for (n /= 2; n != 0; n /= 2) {
a = bmul(a, a);
if (n % 2 != 0) {
z = bmul(z, a);
}
}
return z;
}
// Compute b^(e.w) by splitting it into (b^e)*(b^0.w).
// Use `bpowi` for `b^e` and `bpowK` for k iterations
// of approximation of b^0.w
function bpow(uint256 base, uint256 exp) internal pure returns (uint256) {
require(base >= MIN_BPOW_BASE, "ERR_BPOW_BASE_TOO_LOW");
require(base <= MAX_BPOW_BASE, "ERR_BPOW_BASE_TOO_HIGH");
uint256 whole = bfloor(exp);
uint256 remain = bsub(exp, whole);
uint256 wholePow = bpowi(base, btoi(whole));
if (remain == 0) {
return wholePow;
}
uint256 partialResult = bpowApprox(base, remain, BPOW_PRECISION);
return bmul(wholePow, partialResult);
}
function bpowApprox(
uint256 base,
uint256 exp,
uint256 precision
) internal pure returns (uint256) {
// term 0:
uint256 a = exp;
(uint256 x, bool xneg) = bsubSign(base, BONE);
uint256 term = BONE;
uint256 sum = term;
bool negative = false;
// term(k) = numer / denom
// = (product(a - i - 1, i=1-->k) * x^k) / (k!)
// each iteration, multiply previous term by (a-(k-1)) * x / k
// continue until term is less than precision
for (uint256 i = 1; term >= precision; i++) {
uint256 bigK = i * BONE;
(uint256 c, bool cneg) = bsubSign(a, bsub(bigK, BONE));
term = bmul(term, bmul(c, x));
term = bdiv(term, bigK);
if (term == 0) break;
if (xneg) negative = !negative;
if (cneg) negative = !negative;
if (negative) {
sum = bsub(sum, term);
} else {
sum = badd(sum, term);
}
}
return sum;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0;
pragma experimental ABIEncoderV2;
import "@uniswap/lib/contracts/libraries/TransferHelper.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IERC20.sol";
import "@uniswap/v2-periphery/contracts/interfaces/IWETH.sol";
import "@indexed-finance/indexed-core/contracts/interfaces/IIndexPool.sol";
import "./libraries/UniswapV2Library.sol";
import "./BMath.sol";
contract IndexedUniswapRouterMinter is BMath {
address public immutable factory;
address public immutable weth;
constructor(address factory_, address weth_) public {
factory = factory_;
weth = weth_;
}
receive() external payable {
require(msg.sender == weth, "IndexedUniswapRouterMinter: RECEIVED_ETHER");
}
// requires the initial amount to have already been sent to the first pair
function _swap(uint[] memory amounts, address[] memory path) internal {
for (uint i; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0, address token1) = 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]) : address(this);
IUniswapV2Pair(UniswapV2Library.calculatePair(factory, token0, token1)).swap(
amount0Out, amount1Out, to, new bytes(0)
);
}
}
function _mintTokenAmountIn(
address tokenIn,
uint amountIn,
address indexPool,
uint minPoolAmountOut
) internal returns (uint poolAmountOut) {
TransferHelper.safeApprove(tokenIn, indexPool, amountIn);
poolAmountOut = IIndexPool(indexPool).joinswapExternAmountIn(
tokenIn,
amountIn,
minPoolAmountOut
);
TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut);
}
function _mintPoolAmountOut(
address tokenIn,
uint amountIn,
address indexPool,
uint poolAmountOut
) internal {
TransferHelper.safeApprove(tokenIn, indexPool, amountIn);
IIndexPool(indexPool).joinswapPoolAmountOut(
tokenIn,
poolAmountOut,
amountIn
);
TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut);
}
function _tokenInGivenPoolOut(
address indexPool,
address tokenIn,
uint256 poolAmountOut
) internal view returns (uint256 amountIn) {
IIndexPool.Record memory record = IIndexPool(indexPool).getTokenRecord(tokenIn);
if (!record.ready) {
uint256 minimumBalance = IIndexPool(indexPool).getMinimumBalance(tokenIn);
uint256 realToMinRatio = bdiv(
bsub(minimumBalance, record.balance),
minimumBalance
);
uint256 weightPremium = bmul(MIN_WEIGHT / 10, realToMinRatio);
record.balance = minimumBalance;
record.denorm = uint96(badd(MIN_WEIGHT, weightPremium));
}
uint256 totalSupply = IERC20(indexPool).totalSupply();
uint256 totalWeight = IIndexPool(indexPool).getTotalDenormalizedWeight();
uint256 swapFee = IIndexPool(indexPool).getSwapFee();
return calcSingleInGivenPoolOut(
record.balance,
record.denorm,
totalSupply,
totalWeight,
poolAmountOut,
swapFee
);
}
/**
* @dev Swaps ether for each token in `path` using their Uniswap pairs,
* then mints at least `minPoolAmountOut` pool tokens from `indexPool`.
*
* @param path Array of tokens to swap using the Uniswap router.
* @param indexPool Address of the index pool to mint tokens from.
* @param minPoolAmountOut Amount of pool tokens that must be received to not revert.
*/
function swapExactETHForTokensAndMint(
address[] calldata path,
address indexPool,
uint minPoolAmountOut
) external payable returns (uint poolAmountOut) {
require(path[0] == weth, 'IndexedUniswapRouterMinter: INVALID_PATH');
uint[] memory amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path);
IWETH(weth).deposit{value: amounts[0]}();
require(
IWETH(weth).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]),
"IndexedUniswapRouterMinter: WETH_TRANSFER_FAIL"
);
_swap(amounts, path);
uint amountOut = amounts[amounts.length - 1];
return _mintTokenAmountIn(
path[path.length - 1],
amountOut,
indexPool,
minPoolAmountOut
);
}
/**
* @dev Swaps a token for each other token in `path` using their Uniswap pairs,
* then mints at least `minPoolAmountOut` pool tokens from `indexPool`.
*
* @param amountIn Amount of the first token in `path` to swap.
* @param path Array of tokens to swap using the Uniswap router.
* @param indexPool Address of the index pool to mint tokens from.
* @param minPoolAmountOut Amount of pool tokens that must be received to not revert.
*/
function swapExactTokensForTokensAndMint(
uint amountIn,
address[] calldata path,
address indexPool,
uint minPoolAmountOut
) external returns (uint poolAmountOut) {
uint[] memory amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path);
uint amountOut = amounts[amounts.length - 1];
return _mintTokenAmountIn(
path[path.length - 1],
amountOut,
indexPool,
minPoolAmountOut
);
}
/**
* @dev Swaps ether for each token in `path` through Uniswap,
* then mints `poolAmountOut` pool tokens from `indexPool`.
*
* @param path Array of tokens to swap using the Uniswap router.
* @param indexPool Address of the index pool to mint tokens from.
* @param poolAmountOut Amount of pool tokens that must be received to not revert.
*/
function swapETHForTokensAndMintExact(
address[] calldata path,
address indexPool,
uint poolAmountOut
) external payable {
address swapTokenOut = path[path.length - 1];
uint amountOut = _tokenInGivenPoolOut(indexPool, swapTokenOut, poolAmountOut);
require(path[0] == weth, 'IndexedUniswapRouterMinter: INVALID_PATH');
uint[] memory amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= msg.value, 'IndexedUniswapRouterMinter: EXCESSIVE_INPUT_AMOUNT');
IWETH(weth).deposit{value: amounts[0]}();
require(
IWETH(weth).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]),
"IndexedUniswapRouterMinter: WETH_TRANSFER_FAIL"
);
_swap(amounts, path);
// refund dust eth, if any
if (msg.value > amounts[0]) {
TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]);
}
return _mintPoolAmountOut(
swapTokenOut,
amountOut,
indexPool,
poolAmountOut
);
}
/**
* @dev Swaps a token for each other token in `path` through Uniswap,
* then mints at least `poolAmountOut` pool tokens from `indexPool`.
*
* @param amountInMax Maximum amount of the first token in `path` to give.
* @param path Array of tokens to swap using the Uniswap router.
* @param indexPool Address of the index pool to mint tokens from.
* @param poolAmountOut Amount of pool tokens that must be received to not revert.
*/
function swapTokensForTokensAndMintExact(
uint amountInMax,
address[] calldata path,
address indexPool,
uint poolAmountOut
) external {
address swapTokenOut = path[path.length - 1];
uint amountOut = _tokenInGivenPoolOut(indexPool, swapTokenOut, poolAmountOut);
uint[] memory amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path);
require(amounts[0] <= amountInMax, 'IndexedUniswapRouterMinter: EXCESSIVE_INPUT_AMOUNT');
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path);
_mintPoolAmountOut(
swapTokenOut,
amountOut,
indexPool,
poolAmountOut
);
}
function _getSwapAmountsForJoin(
address indexPool,
address intermediate,
address poolToken,
address[] memory path,
uint256 poolRatio
) internal view returns (uint[] memory amounts) {
if (intermediate == address(0)) {
// If no intermediate token is given, set path length to 2 so the other
// functions will not use the 3rd address.
assembly { mstore(path, 2) }
path[1] = poolToken;
} else {
// If an intermediary is given, set path length to 3 so the other
// functions will use all addresses.
assembly { mstore(path, 3) }
path[1] = intermediate;
path[2] = poolToken;
}
uint256 usedBalance = IIndexPool(indexPool).getUsedBalance(poolToken);
uint256 amountToPool = bmul(poolRatio, usedBalance);
amounts = UniswapV2Library.getAmountsIn(factory, amountToPool, path);
}
/**
* @dev Swaps an input token for every underlying token in an index pool,
* then mints `poolAmountOut` pool tokens from the pool.
*
* Up to one intermediary token may be provided in `intermediaries` for each
* underlying token in the index pool.
*
* If a null address is provided as an intermediary, the input token will be
* swapped directly for the output token.
*/
function swapTokensForAllTokensAndMintExact(
address tokenIn,
uint256 amountInMax,
address[] calldata intermediaries,
address indexPool,
uint256 poolAmountOut
) external returns (uint256 amountInTotal) {
address[] memory tokens = IIndexPool(indexPool).getCurrentTokens();
require(
tokens.length == intermediaries.length,
"IndexedUniswapRouterMinter: BAD_ARRAY_LENGTH"
);
uint256[] memory amountsToPool = new uint256[](tokens.length);
uint256 ratio = bdiv(poolAmountOut, IERC20(indexPool).totalSupply());
// Reserve 3 slots in memory for the addresses
address[] memory path = new address[](3);
path[0] = tokenIn;
for (uint256 i = 0; i < tokens.length; i++) {
uint[] memory amounts = _getSwapAmountsForJoin(
indexPool,
intermediaries[i],
tokens[i],
path,
ratio
);
amountInMax = SafeMath.sub(amountInMax, amounts[0], "IndexedUniswapRouterMinter: EXCESSIVE_INPUT_AMOUNT");
TransferHelper.safeTransferFrom(
path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
);
_swap(amounts, path);
uint amountToPool = amounts[amounts.length - 1];
amountsToPool[i] = amountToPool;
amountInTotal = SafeMath.add(amountInTotal, amounts[0]);
TransferHelper.safeApprove(tokens[i], indexPool, amountToPool);
}
IIndexPool(indexPool).joinPool(poolAmountOut, amountsToPool);
TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut);
}
/**
* @dev Swaps ether for every underlying token in an index pool,
* then mints `poolAmountOut` pool tokens from the pool.
*
* Up to one intermediary token may be provided in `intermediaries` for each
* underlying token in the index pool.
*
* If a null address is provided as an intermediary, the input token will be
* swapped directly for the output token.
*/
function swapETHForAllTokensAndMintExact(
address indexPool,
address[] calldata intermediaries,
uint256 poolAmountOut
) external payable returns (uint amountInTotal) {
uint256 amountInMax = msg.value;
IWETH(weth).deposit{value: msg.value}();
address[] memory tokens = IIndexPool(indexPool).getCurrentTokens();
require(
tokens.length == intermediaries.length,
"IndexedUniswapRouterMinter: BAD_ARRAY_LENGTH"
);
uint256[] memory amountsToPool = new uint256[](tokens.length);
uint256 ratio = bdiv(poolAmountOut, IERC20(indexPool).totalSupply());
// Reserve 3 slots in memory for the addresses
address[] memory path = new address[](3);
path[0] = weth;
for (uint256 i = 0; i < tokens.length; i++) {
uint[] memory amounts = _getSwapAmountsForJoin(
indexPool,
intermediaries[i],
tokens[i],
path,
ratio
);
amountInMax = SafeMath.sub(amountInMax, amounts[0], "IndexedUniswapRouterMinter: EXCESSIVE_INPUT_AMOUNT");
require(
IWETH(weth).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]),
"IndexedUniswapRouterMinter: WETH_TRANSFER_FAIL"
);
_swap(amounts, path);
uint amountToPool = amounts[amounts.length - 1];
amountsToPool[i] = amountToPool;
amountInTotal = SafeMath.add(amountInTotal, amounts[0]);
TransferHelper.safeApprove(tokens[i], indexPool, amountToPool);
}
IIndexPool(indexPool).joinPool(poolAmountOut, amountsToPool);
TransferHelper.safeTransfer(indexPool, msg.sender, poolAmountOut);
if (msg.value > amountInTotal) {
uint256 remainder = msg.value - amountInTotal;
IWETH(weth).withdraw(remainder);
TransferHelper.safeTransferETH(msg.sender, remainder);
}
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.6.0;
// 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,
uint256 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::safeApprove: approve failed'
);
}
function safeTransfer(
address token,
address to,
uint256 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::safeTransfer: transfer failed'
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 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::transferFrom: transferFrom failed'
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
}
}
pragma solidity >=0.5.0;
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);
}
pragma solidity >=0.5.0;
interface IWETH {
function deposit() external payable;
function transfer(address to, uint value) external returns (bool);
function withdraw(uint) external;
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
interface IIndexPool {
/**
* @dev Token record data structure
* @param bound is token bound to pool
* @param ready has token been initialized
* @param lastDenormUpdate timestamp of last denorm change
* @param denorm denormalized weight
* @param desiredDenorm desired denormalized weight (used for incremental changes)
* @param index index of address in tokens array
* @param balance token balance
*/
struct Record {
bool bound;
bool ready;
uint40 lastDenormUpdate;
uint96 denorm;
uint96 desiredDenorm;
uint8 index;
uint256 balance;
}
event LOG_SWAP(
address indexed caller,
address indexed tokenIn,
address indexed tokenOut,
uint256 tokenAmountIn,
uint256 tokenAmountOut
);
event LOG_JOIN(
address indexed caller,
address indexed tokenIn,
uint256 tokenAmountIn
);
event LOG_EXIT(
address indexed caller,
address indexed tokenOut,
uint256 tokenAmountOut
);
event LOG_DENORM_UPDATED(address indexed token, uint256 newDenorm);
event LOG_DESIRED_DENORM_SET(address indexed token, uint256 desiredDenorm);
event LOG_TOKEN_REMOVED(address token);
event LOG_TOKEN_ADDED(
address indexed token,
uint256 desiredDenorm,
uint256 minimumBalance
);
event LOG_MINIMUM_BALANCE_UPDATED(address token, uint256 minimumBalance);
event LOG_TOKEN_READY(address indexed token);
event LOG_PUBLIC_SWAP_ENABLED();
event LOG_MAX_TOKENS_UPDATED(uint256 maxPoolTokens);
event LOG_SWAP_FEE_UPDATED(uint256 swapFee);
function configure(
address controller,
string calldata name,
string calldata symbol
) external;
function initialize(
address[] calldata tokens,
uint256[] calldata balances,
uint96[] calldata denorms,
address tokenProvider,
address unbindHandler
) external;
function setMaxPoolTokens(uint256 maxPoolTokens) external;
function setSwapFee(uint256 swapFee) external;
function reweighTokens(
address[] calldata tokens,
uint96[] calldata desiredDenorms
) external;
function reindexTokens(
address[] calldata tokens,
uint96[] calldata desiredDenorms,
uint256[] calldata minimumBalances
) external;
function setMinimumBalance(address token, uint256 minimumBalance) external;
function joinPool(uint256 poolAmountOut, uint256[] calldata maxAmountsIn) external;
function joinswapExternAmountIn(
address tokenIn,
uint256 tokenAmountIn,
uint256 minPoolAmountOut
) external returns (uint256/* poolAmountOut */);
function joinswapPoolAmountOut(
address tokenIn,
uint256 poolAmountOut,
uint256 maxAmountIn
) external returns (uint256/* tokenAmountIn */);
function exitPool(uint256 poolAmountIn, uint256[] calldata minAmountsOut) external;
function exitswapPoolAmountIn(
address tokenOut,
uint256 poolAmountIn,
uint256 minAmountOut
)
external returns (uint256/* tokenAmountOut */);
function exitswapExternAmountOut(
address tokenOut,
uint256 tokenAmountOut,
uint256 maxPoolAmountIn
) external returns (uint256/* poolAmountIn */);
function gulp(address token) external;
function flashBorrow(
address recipient,
address token,
uint256 amount,
bytes calldata data
) external;
function swapExactAmountIn(
address tokenIn,
uint256 tokenAmountIn,
address tokenOut,
uint256 minAmountOut,
uint256 maxPrice
) external returns (uint256/* tokenAmountOut */, uint256/* spotPriceAfter */);
function swapExactAmountOut(
address tokenIn,
uint256 maxAmountIn,
address tokenOut,
uint256 tokenAmountOut,
uint256 maxPrice
) external returns (uint256 /* tokenAmountIn */, uint256 /* spotPriceAfter */);
function isPublicSwap() external view returns (bool);
function getSwapFee() external view returns (uint256/* swapFee */);
function getController() external view returns (address);
function getMaxPoolTokens() external view returns (uint256);
function isBound(address t) external view returns (bool);
function getNumTokens() external view returns (uint256);
function getCurrentTokens() external view returns (address[] memory tokens);
function getCurrentDesiredTokens() external view returns (address[] memory tokens);
function getDenormalizedWeight(address token) external view returns (uint256/* denorm */);
function getTokenRecord(address token) external view returns (Record memory record);
function extrapolatePoolValueFromToken() external view returns (address/* token */, uint256/* extrapolatedValue */);
function getTotalDenormalizedWeight() external view returns (uint256);
function getBalance(address token) external view returns (uint256);
function getMinimumBalance(address token) external view returns (uint256);
function getUsedBalance(address token) external view returns (uint256);
function getSpotPrice(address tokenIn, address tokenOut) external view returns (uint256);
}
pragma solidity >=0.5.0;
import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
library UniswapV2Library {
using SafeMath 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, "UniswapV2Library: IDENTICAL_ADDRESSES");
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS");
}
function calculatePair(
address factory,
address token0,
address token1
) internal pure returns (address pair) {
pair = address(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1)),
hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f" // init code hash
)
)
)
);
}
// 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 = calculatePair(factory, token0, token1);
}
// 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 some amount of an asset and pair reserves, returns an equivalent amount of the other asset
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) internal pure returns (uint256 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(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountOut) {
require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT");
require(
reserveIn > 0 && reserveOut > 0,
"UniswapV2Library: INSUFFICIENT_LIQUIDITY"
);
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, "UniswapV2Library: INSUFFICIENT_OUTPUT_AMOUNT");
require(
reserveIn > 0 && reserveOut > 0,
"UniswapV2Library: INSUFFICIENT_LIQUIDITY"
);
uint256 numerator = reserveIn.mul(amountOut).mul(1000);
uint256 denominator = reserveOut.sub(amountOut).mul(997);
amountIn = (numerator / denominator).add(1);
}
// performs chained getAmountOut calculations on any number of pairs
function getAmountsOut(
address factory,
uint256 amountIn,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, "UniswapV2Library: INVALID_PATH");
amounts = new uint256[](path.length);
amounts[0] = amountIn;
for (uint256 i; i < path.length - 1; i++) {
(uint256 reserveIn, uint256 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,
uint256 amountOut,
address[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, "UniswapV2Library: INVALID_PATH");
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);
}
}
}
pragma solidity >=0.5.0;
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 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;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}