// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in// construction, since the code is only stored at the end of the// constructor execution.uint256 size;
// solhint-disable-next-line no-inline-assemblyassembly { size :=extcodesize(account) }
return size >0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
require(address(this).balance>= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data, stringmemory errorMessage) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value, stringmemory errorMessage) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data, stringmemory errorMessage) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data, stringmemory errorMessage) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function_verifyCallResult(bool success, bytesmemory returndata, stringmemory errorMessage) privatepurereturns(bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly// solhint-disable-next-line no-inline-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
Contract Source Code
File 2 of 32: Context.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (addresspayable) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytesmemory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691returnmsg.data;
}
}
Contract Source Code
File 3 of 32: DEXAdapterV3.sol
/*
Copyright 2024 Index Cooperative
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import { IUniswapV2Router02 } from"@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import { IERC20 } from"@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from"@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { SafeMath } from"@openzeppelin/contracts/math/SafeMath.sol";
import { ICurveCalculator } from"../interfaces/external/ICurveCalculator.sol";
import { ICurveAddressProvider } from"../interfaces/external/ICurveAddressProvider.sol";
import { ICurvePoolRegistry } from"../interfaces/external/ICurvePoolRegistry.sol";
import { ICurvePool } from"../interfaces/external/ICurvePool.sol";
import { ISwapRouter02 } from"../interfaces/external/ISwapRouter02.sol";
import { IVault } from"../interfaces/external/balancer-v2/IVault.sol";
import { IQuoter } from"../interfaces/IQuoter.sol";
import { IWETH } from"../interfaces/IWETH.sol";
import { PreciseUnitMath } from"../lib/PreciseUnitMath.sol";
/**
* @title DEXAdapterV3
* @author Index Coop
*
* Same as DEXAdapterV2 but adds BalancerV2 support
*/libraryDEXAdapterV3{
usingSafeERC20forIERC20;
usingPreciseUnitMathforuint256;
usingSafeMathforuint256;
/* ============ Constants ============= */uint256constantprivate MAX_UINT256 =type(uint256).max;
addresspublicconstant ETH_ADDRESS =0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256publicconstant ROUNDING_ERROR_MARGIN =2;
/* ============ Enums ============ */enumExchange { None, Quickswap, Sushiswap, UniV3, Curve, BalancerV2 }
/* ============ Structs ============ */structAddresses {
address quickRouter;
address sushiRouter;
address uniV3Router;
address uniV3Quoter;
address curveAddressProvider;
address curveCalculator;
address balV2Vault;
// Wrapped native token (WMATIC on polygon)address weth;
}
structSwapData {
address[] path;
uint24[] fees;
address pool; // For Curve swapsbytes32[] poolIds; // For Balancer V2 multihop swaps
Exchange exchange;
}
structCurvePoolData {
int128 nCoins;
uint256[8] balances;
uint256 A;
uint256 fee;
uint256[8] rates;
uint256[8] decimals;
}
/**
* Swap exact tokens for another token on a given DEX.
*
* @param _addresses Struct containing relevant smart contract addresses.
* @param _amountIn The amount of input token to be spent
* @param _minAmountOut Minimum amount of output token to receive
* @param _swapData Swap data containing the path, fees, pool, and pool IDs
*
* @return amountOut The amount of output tokens
*/functionswapExactTokensForTokens(
Addresses memory _addresses,
uint256 _amountIn,
uint256 _minAmountOut,
SwapData memory _swapData
)
externalreturns (uint256)
{
if (_swapData.path.length==0|| _swapData.path[0] == _swapData.path[_swapData.path.length-1]) {
return _amountIn;
}
if(_swapData.exchange == Exchange.Curve){
return _swapExactTokensForTokensCurve(
_swapData.path,
_swapData.pool,
_amountIn,
_minAmountOut,
_addresses
);
}
if(_swapData.exchange== Exchange.UniV3){
return _swapExactTokensForTokensUniV3(
_swapData.path,
_swapData.fees,
_amountIn,
_minAmountOut,
ISwapRouter02(_addresses.uniV3Router)
);
}
if(_swapData.exchange == Exchange.BalancerV2){
return _swapExactTokensForTokensBalancerV2(
_swapData.path,
_amountIn,
_minAmountOut,
_swapData.poolIds,
IVault(_addresses.balV2Vault)
);
} else {
return _swapExactTokensForTokensUniV2(
_swapData.path,
_amountIn,
_minAmountOut,
_getRouter(_swapData.exchange, _addresses)
);
}
}
/**
* Swap tokens for exact amount of output tokens on a given DEX.
*
* @param _addresses Struct containing relevant smart contract addresses.
* @param _amountOut The amount of output token required
* @param _maxAmountIn Maximum amount of input token to be spent
* @param _swapData Swap data containing the path, fees, pool, and pool IDs
*
* @return amountIn The amount of input tokens spent
*/functionswapTokensForExactTokens(
Addresses memory _addresses,
uint256 _amountOut,
uint256 _maxAmountIn,
SwapData memory _swapData
)
externalreturns (uint256 amountIn)
{
if (_swapData.path.length==0|| _swapData.path[0] == _swapData.path[_swapData.path.length-1]) {
return _amountOut;
}
if(_swapData.exchange == Exchange.Curve){
return _swapTokensForExactTokensCurve(
_swapData.path,
_swapData.pool,
_amountOut,
_maxAmountIn,
_addresses
);
}
if(_swapData.exchange == Exchange.UniV3){
return _swapTokensForExactTokensUniV3(
_swapData.path,
_swapData.fees,
_amountOut,
_maxAmountIn,
ISwapRouter02(_addresses.uniV3Router)
);
}
if(_swapData.exchange == Exchange.BalancerV2){
return _swapTokensForExactTokensBalancerV2(
_swapData.path,
_amountOut,
_maxAmountIn,
_swapData.poolIds,
IVault(_addresses.balV2Vault)
);
} else {
return _swapTokensForExactTokensUniV2(
_swapData.path,
_amountOut,
_maxAmountIn,
_getRouter(_swapData.exchange, _addresses)
);
}
}
/**
* Gets the output amount of a token swap.
*
* @param _swapData the swap parameters
* @param _addresses Struct containing relevant smart contract addresses.
* @param _amountIn the input amount of the trade
*
* @return the output amount of the swap
*/functiongetAmountOut(
Addresses memory _addresses,
SwapData memory _swapData,
uint256 _amountIn
)
externalreturns (uint256)
{
if (_swapData.path.length==0|| _swapData.path[0] == _swapData.path[_swapData.path.length-1]) {
return _amountIn;
}
if (_swapData.exchange == Exchange.UniV3) {
return _getAmountOutUniV3(_swapData, _addresses.uniV3Quoter, _amountIn);
} elseif (_swapData.exchange == Exchange.Curve) {
(int128 i, int128 j) = _getCoinIndices(
_swapData.pool,
_swapData.path[0],
_swapData.path[1],
ICurveAddressProvider(_addresses.curveAddressProvider)
);
return _getAmountOutCurve(_swapData.pool, i, j, _amountIn, _addresses);
} elseif (_swapData.exchange == Exchange.BalancerV2) {
return _getAmountOutBalancerV2(
_swapData,
_addresses,
_amountIn
);
} else {
return _getAmountOutUniV2(
_swapData,
_getRouter(_swapData.exchange, _addresses),
_amountIn
);
}
}
/**
* Gets the input amount of a fixed output swap.
*
* @param _swapData the swap parameters
* @param _addresses Struct containing relevant smart contract addresses.
* @param _amountOut the output amount of the swap
*
* @return the input amount of the swap
*/functiongetAmountIn(
Addresses memory _addresses,
SwapData memory _swapData,
uint256 _amountOut
)
externalreturns (uint256)
{
if (_swapData.path.length==0|| _swapData.path[0] == _swapData.path[_swapData.path.length-1]) {
return _amountOut;
}
if (_swapData.exchange == Exchange.UniV3) {
return _getAmountInUniV3(_swapData, _addresses.uniV3Quoter, _amountOut);
} elseif (_swapData.exchange == Exchange.Curve) {
(int128 i, int128 j) = _getCoinIndices(
_swapData.pool,
_swapData.path[0],
_swapData.path[1],
ICurveAddressProvider(_addresses.curveAddressProvider)
);
return _getAmountInCurve(_swapData.pool, i, j, _amountOut, _addresses);
} elseif (_swapData.exchange == Exchange.BalancerV2) {
return _getAmountInBalancerV2(
_swapData,
_addresses,
_amountOut
);
} else {
return _getAmountInUniV2(
_swapData,
_getRouter(_swapData.exchange, _addresses),
_amountOut
);
}
}
/**
* Sets a max approval limit for an ERC20 token, provided the current allowance
* is less than the required allownce.
*
* @param _token Token to approve
* @param _spender Spender address to approve
* @param _requiredAllowance Target allowance to set
*/function_safeApprove(
IERC20 _token,
address _spender,
uint256 _requiredAllowance
)
internal{
uint256 allowance = _token.allowance(address(this), _spender);
if (allowance < _requiredAllowance) {
_token.safeIncreaseAllowance(_spender, MAX_UINT256 - allowance);
}
}
/* ============ Private Methods ============ *//**
* Execute exact output swap via a UniV2 based DEX. (such as sushiswap);
*
* @param _path List of token address to swap via.
* @param _amountOut The amount of output token required
* @param _maxAmountIn Maximum amount of input token to be spent
* @param _router Address of the uniV2 router to use
*
* @return amountIn The amount of input tokens spent
*/function_swapTokensForExactTokensUniV2(address[] memory _path,
uint256 _amountOut,
uint256 _maxAmountIn,
IUniswapV2Router02 _router
)
privatereturns (uint256)
{
_safeApprove(IERC20(_path[0]), address(_router), _maxAmountIn);
return _router.swapTokensForExactTokens(_amountOut, _maxAmountIn, _path, address(this), block.timestamp)[0];
}
/**
* Execute exact output swap via UniswapV3
*
* @param _path List of token address to swap via. (In the order as
* expected by uniV2, the first element being the input toen)
* @param _fees List of fee levels identifying the pools to swap via.
* (_fees[0] refers to pool between _path[0] and _path[1])
* @param _amountOut The amount of output token required
* @param _maxAmountIn Maximum amount of input token to be spent
* @param _uniV3Router Address of the uniswapV3 router
*
* @return amountIn The amount of input tokens spent
*/function_swapTokensForExactTokensUniV3(address[] memory _path,
uint24[] memory _fees,
uint256 _amountOut,
uint256 _maxAmountIn,
ISwapRouter02 _uniV3Router
)
privatereturns(uint256)
{
require(_path.length== _fees.length+1, "ExchangeIssuance: PATHS_FEES_MISMATCH");
_safeApprove(IERC20(_path[0]), address(_uniV3Router), _maxAmountIn);
if(_path.length==2){
ISwapRouter02.ExactOutputSingleParams memory params =
ISwapRouter02.ExactOutputSingleParams({
tokenIn: _path[0],
tokenOut: _path[1],
fee: _fees[0],
recipient: address(this),
amountOut: _amountOut,
amountInMaximum: _maxAmountIn,
sqrtPriceLimitX96: 0
});
return _uniV3Router.exactOutputSingle(params);
} else {
bytesmemory pathV3 = _encodePathV3(_path, _fees, true);
ISwapRouter02.ExactOutputParams memory params =
ISwapRouter02.ExactOutputParams({
path: pathV3,
recipient: address(this),
amountOut: _amountOut,
amountInMaximum: _maxAmountIn
});
return _uniV3Router.exactOutput(params);
}
}
/**
* Execute exact input swap via Curve
*
* @param _path Path (has to be of length 2)
* @param _pool Address of curve pool to use
* @param _amountIn The amount of input token to be spent
* @param _minAmountOut Minimum amount of output token to receive
* @param _addresses Struct containing relevant smart contract addresses.
*
* @return amountOut The amount of output token obtained
*/function_swapExactTokensForTokensCurve(address[] memory _path,
address _pool,
uint256 _amountIn,
uint256 _minAmountOut,
Addresses memory _addresses
)
privatereturns (uint256 amountOut)
{
require(_path.length==2, "ExchangeIssuance: CURVE_WRONG_PATH_LENGTH");
(int128 i, int128 j) = _getCoinIndices(_pool, _path[0], _path[1], ICurveAddressProvider(_addresses.curveAddressProvider));
amountOut = _exchangeCurve(i, j, _pool, _amountIn, _minAmountOut, _path[0]);
}
/**
* Execute exact output swap via Curve
*
* @param _path Path (has to be of length 2)
* @param _pool Address of curve pool to use
* @param _amountOut The amount of output token required
* @param _maxAmountIn Maximum amount of input token to be spent
*
* @return amountOut The amount of output token obtained
*/function_swapTokensForExactTokensCurve(address[] memory _path,
address _pool,
uint256 _amountOut,
uint256 _maxAmountIn,
Addresses memory _addresses
)
privatereturns (uint256)
{
require(_path.length==2, "ExchangeIssuance: CURVE_WRONG_PATH_LENGTH");
(int128 i, int128 j) = _getCoinIndices(_pool, _path[0], _path[1], ICurveAddressProvider(_addresses.curveAddressProvider));
uint256 returnedAmountOut = _exchangeCurve(i, j, _pool, _maxAmountIn, _amountOut, _path[0]);
require(_amountOut <= returnedAmountOut, "ExchangeIssuance: CURVE_UNDERBOUGHT");
uint256 swappedBackAmountIn;
if(returnedAmountOut > _amountOut){
swappedBackAmountIn = _exchangeCurve(j, i, _pool, returnedAmountOut.sub(_amountOut), 0, _path[1]);
}
return _maxAmountIn.sub(swappedBackAmountIn);
}
function_exchangeCurve(int128 _i,
int128 _j,
address _pool,
uint256 _amountIn,
uint256 _minAmountOut,
address _from
)
privatereturns (uint256 amountOut)
{
ICurvePool pool = ICurvePool(_pool);
if(_from == ETH_ADDRESS){
amountOut = pool.exchange{value: _amountIn}(
_i,
_j,
_amountIn,
_minAmountOut
);
}
else {
IERC20(_from).approve(_pool, _amountIn);
amountOut = pool.exchange(
_i,
_j,
_amountIn,
_minAmountOut
);
}
}
/**
* Calculate required input amount to get a given output amount via Curve swap
*
* @param _i Index of input token as per the ordering of the pools tokens
* @param _j Index of output token as per the ordering of the pools tokens
* @param _pool Address of curve pool to use
* @param _amountOut The amount of output token to be received
* @param _addresses Struct containing relevant smart contract addresses.
*
* @return amountOut The amount of output token obtained
*/function_getAmountInCurve(address _pool,
int128 _i,
int128 _j,
uint256 _amountOut,
Addresses memory _addresses
)
privateviewreturns (uint256)
{
CurvePoolData memory poolData = _getCurvePoolData(_pool, ICurveAddressProvider(_addresses.curveAddressProvider));
return ICurveCalculator(_addresses.curveCalculator).get_dx(
poolData.nCoins,
poolData.balances,
poolData.A,
poolData.fee,
poolData.rates,
poolData.decimals,
false,
_i,
_j,
_amountOut
) + ROUNDING_ERROR_MARGIN;
}
/**
* Calculate output amount of a Curve swap
*
* @param _i Index of input token as per the ordering of the pools tokens
* @param _j Index of output token as per the ordering of the pools tokens
* @param _pool Address of curve pool to use
* @param _amountIn The amount of output token to be received
* @param _addresses Struct containing relevant smart contract addresses.
*
* @return amountOut The amount of output token obtained
*/function_getAmountOutCurve(address _pool,
int128 _i,
int128 _j,
uint256 _amountIn,
Addresses memory _addresses
)
privateviewreturns (uint256)
{
return ICurvePool(_pool).get_dy(_i, _j, _amountIn);
}
/**
* Get metadata on curve pool required to calculate input amount from output amount
*
* @param _pool Address of curve pool to use
* @param _curveAddressProvider Address of curve address provider
*
* @return Struct containing all required data to perform getAmountInCurve calculation
*/function_getCurvePoolData(address _pool,
ICurveAddressProvider _curveAddressProvider
) privateviewreturns(CurvePoolData memory)
{
ICurvePoolRegistry registry = ICurvePoolRegistry(_curveAddressProvider.get_registry());
return CurvePoolData(
int128(registry.get_n_coins(_pool)[0]),
registry.get_balances(_pool),
registry.get_A(_pool),
registry.get_fees(_pool)[0],
registry.get_rates(_pool),
registry.get_decimals(_pool)
);
}
/**
* Get token indices for given pool
* NOTE: This was necessary sine the get_coin_indices function of the CurvePoolRegistry did not work for StEth/ETH pool
*
* @param _pool Address of curve pool to use
* @param _from Address of input token
* @param _to Address of output token
* @param _curveAddressProvider Address of curve address provider
*
* @return i Index of input token
* @return j Index of output token
*/function_getCoinIndices(address _pool,
address _from,
address _to,
ICurveAddressProvider _curveAddressProvider
)
privateviewreturns (int128 i, int128 j)
{
ICurvePoolRegistry registry = ICurvePoolRegistry(_curveAddressProvider.get_registry());
// Set to out of range index to signal the coin is not found yet
i =9;
j =9;
address[8] memory poolCoins = registry.get_coins(_pool);
for(uint256 k =0; k <8; k++){
if(poolCoins[k] == _from){
i =int128(k);
}
elseif(poolCoins[k] == _to){
j =int128(k);
}
// ZeroAddress signals end of listif(poolCoins[k] ==address(0) || (i !=9&& j !=9)){
break;
}
}
require(i !=9, "ExchangeIssuance: CURVE_FROM_NOT_FOUND");
require(j !=9, "ExchangeIssuance: CURVE_TO_NOT_FOUND");
return (i, j);
}
/**
* Execute exact input swap via UniswapV3
*
* @param _path List of token address to swap via.
* @param _fees List of fee levels identifying the pools to swap via.
* (_fees[0] refers to pool between _path[0] and _path[1])
* @param _amountIn The amount of input token to be spent
* @param _minAmountOut Minimum amount of output token to receive
* @param _uniV3Router Address of the uniswapV3 router
*
* @return amountOut The amount of output token obtained
*/function_swapExactTokensForTokensUniV3(address[] memory _path,
uint24[] memory _fees,
uint256 _amountIn,
uint256 _minAmountOut,
ISwapRouter02 _uniV3Router
)
privatereturns (uint256)
{
require(_path.length== _fees.length+1, "ExchangeIssuance: PATHS_FEES_MISMATCH");
_safeApprove(IERC20(_path[0]), address(_uniV3Router), _amountIn);
if(_path.length==2){
ISwapRouter02.ExactInputSingleParams memory params =
ISwapRouter02.ExactInputSingleParams({
tokenIn: _path[0],
tokenOut: _path[1],
fee: _fees[0],
recipient: address(this),
amountIn: _amountIn,
amountOutMinimum: _minAmountOut,
sqrtPriceLimitX96: 0
});
return _uniV3Router.exactInputSingle(params);
} else {
bytesmemory pathV3 = _encodePathV3(_path, _fees, false);
ISwapRouter02.ExactInputParams memory params =
ISwapRouter02.ExactInputParams({
path: pathV3,
recipient: address(this),
amountIn: _amountIn,
amountOutMinimum: _minAmountOut
});
uint amountOut = _uniV3Router.exactInput(params);
return amountOut;
}
}
/**
* Execute exact input swap via UniswapV2
*
* @param _path List of token address to swap via.
* @param _amountIn The amount of input token to be spent
* @param _minAmountOut Minimum amount of output token to receive
* @param _router Address of uniV2 router to use
*
* @return amountOut The amount of output token obtained
*/function_swapExactTokensForTokensUniV2(address[] memory _path,
uint256 _amountIn,
uint256 _minAmountOut,
IUniswapV2Router02 _router
)
privatereturns (uint256)
{
_safeApprove(IERC20(_path[0]), address(_router), _amountIn);
// NOTE: The following was changed from always returning result at position [1] to returning the last element of the result array// With this change, the actual output is correctly returned also for multi-hop swaps// See https://github.com/IndexCoop/index-coop-smart-contracts/pull/116 uint256[] memory result = _router.swapExactTokensForTokens(_amountIn, _minAmountOut, _path, address(this), block.timestamp);
// result = uint[] memory The input token amount and all subsequent output token amounts.// we are usually only interested in the actual amount of the output token (so result element at the last place)return result[result.length-1];
}
/**
* Gets the output amount of a token swap on Uniswap V2
*
* @param _swapData the swap parameters
* @param _router the uniswap v2 router address
* @param _amountIn the input amount of the trade
*
* @return the output amount of the swap
*/function_getAmountOutUniV2(
SwapData memory _swapData,
IUniswapV2Router02 _router,
uint256 _amountIn
)
privateviewreturns (uint256)
{
return _router.getAmountsOut(_amountIn, _swapData.path)[_swapData.path.length-1];
}
/**
* Gets the input amount of a fixed output swap on Uniswap V2.
*
* @param _swapData the swap parameters
* @param _router the uniswap v2 router address
* @param _amountOut the output amount of the swap
*
* @return the input amount of the swap
*/function_getAmountInUniV2(
SwapData memory _swapData,
IUniswapV2Router02 _router,
uint256 _amountOut
)
privateviewreturns (uint256)
{
return _router.getAmountsIn(_amountOut, _swapData.path)[0];
}
/**
* Gets the output amount of a token swap on Uniswap V3.
*
* @param _swapData the swap parameters
* @param _quoter the uniswap v3 quoter
* @param _amountIn the input amount of the trade
*
* @return the output amount of the swap
*/function_getAmountOutUniV3(
SwapData memory _swapData,
address _quoter,
uint256 _amountIn
)
privatereturns (uint256)
{
bytesmemory path = _encodePathV3(_swapData.path, _swapData.fees, false);
return IQuoter(_quoter).quoteExactInput(path, _amountIn);
}
/**
* Gets the input amount of a fixed output swap on Uniswap V3.
*
* @param _swapData the swap parameters
* @param _quoter uniswap v3 quoter
* @param _amountOut the output amount of the swap
*
* @return the input amount of the swap
*/function_getAmountInUniV3(
SwapData memory _swapData,
address _quoter,
uint256 _amountOut
)
privatereturns (uint256)
{
bytesmemory path = _encodePathV3(_swapData.path, _swapData.fees, true);
return IQuoter(_quoter).quoteExactOutput(path, _amountOut);
}
/**
* Encode path / fees to bytes in the format expected by UniV3 router
*
* @param _path List of token address to swap via (starting with input token)
* @param _fees List of fee levels identifying the pools to swap via.
* (_fees[0] refers to pool between _path[0] and _path[1])
* @param _reverseOrder Boolean indicating if path needs to be reversed to start with output token.
* (which is the case for exact output swap)
*
* @return encodedPath Encoded path to be forwared to uniV3 router
*/function_encodePathV3(address[] memory _path,
uint24[] memory _fees,
bool _reverseOrder
)
privatepurereturns(bytesmemory encodedPath)
{
if(_reverseOrder){
encodedPath =abi.encodePacked(_path[_path.length-1]);
for(uint i =0; i < _fees.length; i++){
uint index = _fees.length- i -1;
encodedPath =abi.encodePacked(encodedPath, _fees[index], _path[index]);
}
} else {
encodedPath =abi.encodePacked(_path[0]);
for(uint i =0; i < _fees.length; i++){
encodedPath =abi.encodePacked(encodedPath, _fees[i], _path[i+1]);
}
}
}
function_getRouter(
Exchange _exchange,
Addresses memory _addresses
)
privatepurereturns (IUniswapV2Router02)
{
return IUniswapV2Router02(
(_exchange == Exchange.Quickswap) ? _addresses.quickRouter : _addresses.sushiRouter
);
}
/**
* Execute exact input swap via Balancer V2 (supports multihop swaps)
*
* @param _path List of token addresses to swap via.
* @param _amountIn The amount of input token to be spent
* @param _minAmountOut Minimum amount of output token to receive
* @param _poolIds List of pool IDs for each swap step
* @param _vault Address of the Balancer V2 Vault
*
* @return amountOut The amount of output tokens received
*/function_swapExactTokensForTokensBalancerV2(address[] memory _path,
uint256 _amountIn,
uint256 _minAmountOut,
bytes32[] memory _poolIds,
IVault _vault
)
privatereturns (uint256 amountOut)
{
require(_path.length>=2, "DEXAdapterV3: BALANCER_PATH_LENGTH");
require(_poolIds.length== _path.length-1, "DEXAdapterV3: INVALID_POOL_IDS");
// Approve the Vault to spend the input token
_safeApprove(IERC20(_path[0]), address(_vault), _amountIn);
// Build the assets array (unique tokens in the path)address[] memory assets = _getAssets(_path);
// Build the swaps array
IVault.BatchSwapStep[] memory swaps =new IVault.BatchSwapStep[](_path.length-1);
for (uint256 i =0; i < _path.length-1; i++) {
swaps[i] = IVault.BatchSwapStep({
poolId: _poolIds[i],
assetInIndex: _getAssetIndex(assets, _path[i]),
assetOutIndex: _getAssetIndex(assets, _path[i +1]),
amount: i ==0 ? _amountIn : 0, // Only specify amount for first swap
userData: ""
});
}
// Set up funds
IVault.FundManagement memory funds = IVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
});
// Set up limitsint256[] memory limits =newint256[](assets.length);
for (uint256 i =0; i < assets.length; i++) {
if (assets[i] == _path[0]) {
limits[i] =int256(_amountIn);
} elseif (assets[i] == _path[_path.length-1]) {
limits[i] =-int256(_minAmountOut);
} else {
limits[i] =0;
}
}
// Perform the batch swapint256[] memory deltas = _vault.batchSwap(
IVault.SwapKind.GIVEN_IN,
swaps,
assets,
funds,
limits,
block.timestamp
);
amountOut =uint256(-deltas[_getAssetIndex(assets, _path[_path.length-1])]);
require(amountOut >= _minAmountOut, "DEXAdapterV3: INSUFFICIENT_OUTPUT_AMOUNT");
}
/**
* Execute exact output swap via Balancer V2 (supports multihop swaps)
*
* @param _path List of token addresses to swap via.
* @param _amountOut The amount of output token required
* @param _maxAmountIn Maximum amount of input token to be spent
* @param _poolIds List of pool IDs for each swap step
* @param _vault Address of the Balancer V2 Vault
*
* @return amountIn The amount of input tokens spent
*/function_swapTokensForExactTokensBalancerV2(address[] memory _path,
uint256 _amountOut,
uint256 _maxAmountIn,
bytes32[] memory _poolIds,
IVault _vault
)
privatereturns (uint256 amountIn)
{
require(_path.length>=2, "DEXAdapterV3: BALANCER_PATH_LENGTH");
require(_poolIds.length== _path.length-1, "DEXAdapterV3: INVALID_POOL_IDS");
// Approve the Vault to spend the input token
_safeApprove(IERC20(_path[0]), address(_vault), _maxAmountIn);
// Build the assets array (unique tokens in the path)address[] memory assets = _getAssets(_path);
// Build the swaps array
IVault.BatchSwapStep[] memory swaps =new IVault.BatchSwapStep[](_path.length-1);
for (uint256 i =0; i < _path.length-1; i++) {
swaps[i] = IVault.BatchSwapStep({
poolId: _poolIds[i],
assetInIndex: _getAssetIndex(assets, _path[i]),
assetOutIndex: _getAssetIndex(assets, _path[i +1]),
amount: 0, // Amount is determined by the Vault
userData: ""
});
}
// Set up funds
IVault.FundManagement memory funds = IVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
});
// Set up limitsint256[] memory limits =newint256[](assets.length);
for (uint256 i =0; i < assets.length; i++) {
if (assets[i] == _path[0]) {
limits[i] =int256(_maxAmountIn);
} elseif (assets[i] == _path[_path.length-1]) {
limits[i] =-int256(_amountOut);
} else {
limits[i] =0;
}
}
// Perform the batch swapint256[] memory deltas = _vault.batchSwap(
IVault.SwapKind.GIVEN_OUT,
swaps,
assets,
funds,
limits,
block.timestamp
);
amountIn =uint256(deltas[_getAssetIndex(assets, _path[0])]);
require(amountIn <= _maxAmountIn, "DEXAdapterV3: EXCESSIVE_INPUT_AMOUNT");
}
/**
* Gets the output amount of a token swap on Balancer V2 using queryBatchSwap.
*
* @param _swapData the swap parameters
* @param _addresses Struct containing relevant smart contract addresses
* @param _amountIn the input amount of the trade
*
* @return amountOut the output amount of the swap
*/function_getAmountOutBalancerV2(
SwapData memory _swapData,
Addresses memory _addresses,
uint256 _amountIn
)
privatereturns (uint256 amountOut)
{
IVault _vault = IVault(_addresses.balV2Vault);
// Build the assets array (unique tokens in the path)address[] memory assets = _getAssets(_swapData.path);
// Build the swaps array
IVault.BatchSwapStep[] memory swaps =new IVault.BatchSwapStep[](_swapData.path.length-1);
for (uint256 i =0; i < _swapData.path.length-1; i++) {
swaps[i] = IVault.BatchSwapStep({
poolId: _swapData.poolIds[i],
assetInIndex: _getAssetIndex(assets, _swapData.path[i]),
assetOutIndex: _getAssetIndex(assets, _swapData.path[i +1]),
amount: i ==0 ? _amountIn : 0, // Only specify amount for first swap
userData: ""
});
}
// Set up funds (not used in query)
IVault.FundManagement memory funds = IVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
});
// Perform the queryint256[] memory deltas = _vault.queryBatchSwap(
IVault.SwapKind.GIVEN_IN,
swaps,
assets,
funds
);
amountOut =uint256(-deltas[_getAssetIndex(assets, _swapData.path[_swapData.path.length-1])]);
}
/**
* Gets the input amount of a fixed output swap on Balancer V2 using queryBatchSwap.
*
* @param _swapData the swap parameters
* @param _addresses Struct containing relevant smart contract addresses
* @param _amountOut the output amount of the swap
*
* @return amountIn the input amount of the swap
*/function_getAmountInBalancerV2(
SwapData memory _swapData,
Addresses memory _addresses,
uint256 _amountOut
)
privatereturns (uint256 amountIn)
{
IVault _vault = IVault(_addresses.balV2Vault);
// Build the assets array (unique tokens in the path)address[] memory assets = _getAssets(_swapData.path);
// Build the swaps array
IVault.BatchSwapStep[] memory swaps =new IVault.BatchSwapStep[](_swapData.path.length-1);
for (uint256 i =0; i < _swapData.path.length-1; i++) {
swaps[i] = IVault.BatchSwapStep({
poolId: _swapData.poolIds[i],
assetInIndex: _getAssetIndex(assets, _swapData.path[i]),
assetOutIndex: _getAssetIndex(assets, _swapData.path[i +1]),
amount: i == swaps.length-1 ? _amountOut : 0, // Only specify amount for last swap
userData: ""
});
}
// Set up funds (not used in query)
IVault.FundManagement memory funds = IVault.FundManagement({
sender: address(this),
fromInternalBalance: false,
recipient: payable(address(this)),
toInternalBalance: false
});
// Perform the queryint256[] memory deltas = _vault.queryBatchSwap(
IVault.SwapKind.GIVEN_OUT,
swaps,
assets,
funds
);
amountIn =uint256(deltas[_getAssetIndex(assets, _swapData.path[0])]);
}
/**
* Helper function to get the list of unique assets from the path.
*
* @param _path List of token addresses in the swap path
*
* @return assets List of unique assets
*/function_getAssets(address[] memory _path) privatepurereturns (address[] memory assets) {
uint256 assetCount =0;
address[] memory tempAssets =newaddress[](_path.length);
for (uint256 i =0; i < _path.length; i++) {
bool alreadyAdded =false;
for (uint256 j =0; j < assetCount; j++) {
if (tempAssets[j] == _path[i]) {
alreadyAdded =true;
break;
}
}
if (!alreadyAdded) {
tempAssets[assetCount] = _path[i];
assetCount++;
}
}
assets =newaddress[](assetCount);
for (uint256 i =0; i < assetCount; i++) {
assets[i] = tempAssets[i];
}
}
/**
* Helper function to get the index of an asset in the assets array.
*
* @param assets List of assets
* @param token Token address to find
*
* @return index Index of the token in the assets array
*/function_getAssetIndex(address[] memory assets, address token) privatepurereturns (uint256) {
for (uint256 i =0; i < assets.length; i++) {
if (assets[i] == token) {
return i;
}
}
revert("DEXAdapterV3: TOKEN_NOT_IN_ASSETS");
}
}
Contract Source Code
File 4 of 32: FlashMintHyETHV3.sol
/*
Copyright 2024 Index Cooperative
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import { Address } from"@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from"@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from"@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { SafeMath } from"@openzeppelin/contracts/math/SafeMath.sol";
import { ReentrancyGuard } from"@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IERC4626 } from"../interfaces/IERC4626.sol";
import { IStETH } from"../interfaces/external/IStETH.sol";
import { IAcrossHubPoolV2 } from"../interfaces/external/IAcrossHubPoolV2.sol";
import { IPendlePrincipalToken } from"../interfaces/external/IPendlePrincipalToken.sol";
import { IPendleMarketV3 } from"../interfaces/external/IPendleMarketV3.sol";
import { IPendleStandardizedYield } from"../interfaces/external/IPendleStandardizedYield.sol";
import { IRsEthAdapter } from"../interfaces/external/IRsEthAdapter.sol";
import { IController } from"../interfaces/IController.sol";
import { IDebtIssuanceModule } from"../interfaces/IDebtIssuanceModule.sol";
import { ISetToken } from"../interfaces/ISetToken.sol";
import { IWETH } from"../interfaces/IWETH.sol";
import { Ownable } from"@openzeppelin/contracts/access/Ownable.sol";
import { DEXAdapterV3 } from"./DEXAdapterV3.sol";
/**
* @title FlashMintHyETHV3
*/contractFlashMintHyETHV3isOwnable, ReentrancyGuard{
usingDEXAdapterV3forDEXAdapterV3.Addresses;
usingAddressforaddresspayable;
usingAddressforaddress;
usingSafeMathforuint256;
usingSafeERC20forIERC20;
usingSafeERC20forISetToken;
structPendleMarketData {
IPendlePrincipalToken pt;
IPendleStandardizedYield sy;
address underlying;
uint256 exchangeRateFactor;
}
/* ============ Constants ============= */uint256privateconstant MAX_UINT256 =type(uint256).max;
uint256publicconstant ROUNDING_ERROR =10;
IERC20 publicconstant acrossToken = IERC20(0x28F77208728B0A45cAb24c4868334581Fe86F95B);
IAcrossHubPoolV2 publicconstant acrossPool =
IAcrossHubPoolV2(0xc186fA914353c44b2E33eBE05f21846F1048bEda);
IERC20 publicconstant agETH = IERC20(0xe1B4d34E8754600962Cd944B535180Bd758E6c2e);
IRsEthAdapter publicconstant rsEthAdapter = IRsEthAdapter(0xbf28C9FCb12A97441488f9C68FaA49811a98688a);
/* ============ Immutables ============ */
IController publicimmutable setController;
IStETH publicimmutable stETH;
IDebtIssuanceModule publicimmutable issuanceModule; // interface is compatible with DebtIssuanceModuleV2mapping(IPendlePrincipalToken => IPendleMarketV3) public pendleMarkets;
mapping(IPendleMarketV3 => PendleMarketData) public pendleMarketData;
mapping(address=>mapping(address=> DEXAdapterV3.SwapData)) public swapData;
mapping(address=>bool) public erc4626Components;
/* ============ State Variables ============ */
DEXAdapterV3.Addresses public dexAdapter;
/* ============ Events ============ */eventFlashMint(addressindexed _recipient, // The recipient address of the minted Set token
ISetToken indexed _setToken, // The minted Set token
IERC20 indexed _inputToken, // The address of the input asset(ERC20/ETH) used to mint the Set tokensuint256 _amountInputToken, // The amount of input tokens used for mintinguint256 _amountSetIssued // The amount of Set tokens received by the recipient);
eventFlashRedeem(addressindexed _recipient, // The recipient address which redeemed the Set token
ISetToken indexed _setToken, // The redeemed Set token
IERC20 indexed _outputToken, // The address of output asset(ERC20/ETH) received by the recipientuint256 _amountSetRedeemed, // The amount of Set token redeemed for output tokensuint256 _amountOutputToken // The amount of output tokens received by the recipient);
/* ============ Modifiers ============ *//**
* checks that _setToken is a valid listed set token on the setController
*
* @param _setToken set token to check
*/modifierisSetToken(ISetToken _setToken) {
require(setController.isSet(address(_setToken)), "FlashMint: INVALID_SET");
_;
}
/**
* checks that _inputToken is the first adress in _path and _outputToken is the last address in _path
*
* @param _path Array of addresses for a DEX swap path
* @param _inputToken input token of DEX swap
* @param _outputToken output token of DEX swap
*/modifierisValidPath(address[] memory _path,
address _inputToken,
address _outputToken
) {
if (_inputToken != _outputToken) {
require(
_path[0] == _inputToken ||
(_inputToken == dexAdapter.weth && _path[0] == DEXAdapterV3.ETH_ADDRESS),
"FlashMint: INPUT_TOKEN_NOT_IN_PATH"
);
require(
_path[_path.length-1] == _outputToken ||
(_outputToken == dexAdapter.weth &&
_path[_path.length-1] == DEXAdapterV3.ETH_ADDRESS),
"FlashMint: OUTPUT_TOKEN_NOT_IN_PATH"
);
}
_;
}
/* ========== Constructor ========== */constructor(
DEXAdapterV3.Addresses memory _dexAddresses,
IController _setController,
IDebtIssuanceModule _issuanceModule,
IStETH _stETH,
address _stEthETHPool
) public{
dexAdapter = _dexAddresses;
setController = _setController;
issuanceModule = _issuanceModule;
stETH = _stETH;
IERC20(address(_stETH)).approve(_stEthETHPool, MAX_UINT256);
}
/* ============ External Functions (Publicly Accesible) ============ *//**
* Runs all the necessary approval functions required before issuing
* or redeeming a SetToken. This function needs to be called only once before the first time
* this smart contract is used on any particular SetToken.
*
* @param _setToken Address of the SetToken being initialized
*/functionapproveSetToken(ISetToken _setToken) externalisSetToken(_setToken) {
address[] memory _components = _setToken.getComponents();
for (uint256 i =0; i < _components.length; ++i) {
IERC20(_components[i]).approve(address(issuanceModule), MAX_UINT256);
}
_setToken.approve(address(issuanceModule), MAX_UINT256);
}
/**
* Issue exact amount of SetToken from ETH
*
* @param _setToken Address of the SetToken to issue
* @param _amountSetToken Amount of SetToken to issue
*/functionissueExactSetFromETH(
ISetToken _setToken,
uint256 _amountSetToken,
DEXAdapterV3.SwapData[] memory _swapDataEthToComponent
) externalpayablenonReentrantreturns (uint256) {
uint256 ethSpent = _issueExactSetFromEth(_setToken, _amountSetToken, _swapDataEthToComponent);
msg.sender.sendValue(msg.value.sub(ethSpent));
return ethSpent;
}
/**
* Issue exact amount of SetToken from ERC20 token
*
* @param _setToken Address of the SetToken to issue
* @param _amountSetToken Amount of SetToken to issue
* @param _inputToken Address of the input token
* @param _maxInputTokenAmount Maximum amount of input token to spend
* @param _swapDataInputTokenToEth Swap data from input token to ETH
* @param _swapDataEthToInputToken Swap data from ETH to input token (used to swap back the leftover eth)
*/functionissueExactSetFromERC20(
ISetToken _setToken,
uint256 _amountSetToken,
IERC20 _inputToken,
uint256 _maxInputTokenAmount,
DEXAdapterV3.SwapData memory _swapDataInputTokenToEth,
DEXAdapterV3.SwapData memory _swapDataEthToInputToken,
DEXAdapterV3.SwapData[] memory _swapDataEthToComponent
) externalpayablenonReentrantreturns (uint256) {
_inputToken.safeTransferFrom(msg.sender, address(this), _maxInputTokenAmount);
uint256 ethAmount = _swapExactTokenForEth(_inputToken, _maxInputTokenAmount, _swapDataInputTokenToEth);
ethAmount = ethAmount.sub(_issueExactSetFromEth(_setToken, _amountSetToken, _swapDataEthToComponent));
uint256 inputTokenLeft = _swapFromEthToToken(_inputToken, ethAmount, _swapDataEthToInputToken);
_inputToken.safeTransfer(msg.sender, inputTokenLeft);
return _maxInputTokenAmount.sub(inputTokenLeft);
}
/**
* Redeem exact amount of SetToken for ETH
*
* @param _setToken Address of the SetToken to redeem
* @param _amountSetToken Amount of SetToken to redeem
* @param _minETHOut Minimum amount of ETH to receive (tx will revert if actual amount is less)
* @param _swapDataComponentToEth Swap data from component to ETH (for non-standard components)
*/functionredeemExactSetForETH(
ISetToken _setToken,
uint256 _amountSetToken,
uint256 _minETHOut,
DEXAdapterV3.SwapData[] memory _swapDataComponentToEth
) externalpayablenonReentrantreturns (uint256) {
uint256 ethObtained = _redeemExactSetForETH(_setToken, _amountSetToken, _minETHOut, _swapDataComponentToEth);
require(ethObtained >= _minETHOut, "FlashMint: INSUFFICIENT_OUTPUT");
msg.sender.sendValue(ethObtained);
return ethObtained;
}
/**
* Redeem exact amount of SetToken for ERC20
*
* @param _setToken Address of the SetToken to redeem
* @param _amountSetToken Amount of SetToken to redeem
* @param _outputToken Address of the output token
* @param _minOutputTokenAmount Minimum amount of output token to receive (tx will revert if actual amount is less)
* @param _swapDataEthToOutputToken Swap data from ETH to output token
* @param _swapDataComponentToEth Swap data from component to ETH (for non-standard components)
*/functionredeemExactSetForERC20(
ISetToken _setToken,
uint256 _amountSetToken,
IERC20 _outputToken,
uint256 _minOutputTokenAmount,
DEXAdapterV3.SwapData memory _swapDataEthToOutputToken,
DEXAdapterV3.SwapData[] memory _swapDataComponentToEth
) externalpayablenonReentrantreturns (uint256) {
uint256 ethObtained = _redeemExactSetForETH(_setToken, _amountSetToken, 0, _swapDataComponentToEth);
uint256 outputTokenAmount = _swapFromEthToToken(_outputToken, ethObtained, _swapDataEthToOutputToken);
require(outputTokenAmount >= _minOutputTokenAmount, "FlashMint: INSUFFICIENT_OUTPUT");
_outputToken.safeTransfer(msg.sender, outputTokenAmount);
return outputTokenAmount;
}
receive() externalpayable{}
/* ============ External Functions (Access controlled) ============ *//**
* Control wether a component is registered as an ERC4626 token
*
* @param _component Address of the component
* @param _isERC4626 Boolean indicating if the component is an ERC4626 token
*/functionsetERC4626Component(address _component,
bool _isERC4626
) externalonlyOwner{
erc4626Components[_component] = _isERC4626;
}
/**
* Approve spender to spend specific token on behalf of this contract
*
* @param _token Address of the token to approve
* @param _spender Address of the spender
* @param _allowance Amount to approve
*/functionapproveToken(IERC20 _token, address _spender, uint256 _allowance) externalonlyOwner{
_token.approve(_spender, _allowance);
}
/**
* Withdraw slippage to selected address
*
* @param _tokens Addresses of tokens to withdraw, specify ETH_ADDRESS to withdraw ETH
* @param _to Address to send the tokens to
*/functionwithdrawTokens(
IERC20[] calldata _tokens,
addresspayable _to
) externalpayableonlyOwner{
for (uint256 i =0; i < _tokens.length; i++) {
if (address(_tokens[i]) == DEXAdapterV3.ETH_ADDRESS) {
_to.sendValue(address(this).balance);
} else {
_tokens[i].safeTransfer(_to, _tokens[i].balanceOf(address(this)));
}
}
}
/**
* Set swap data for specific token pair
*
* @param _inputToken Address of the input token
* @param _outputToken Address of the output token
* @param _swapData Swap data for the token pair describing DEX / route
*/functionsetSwapData(address _inputToken,
address _outputToken,
DEXAdapterV3.SwapData memory _swapData
) externalonlyOwner{
swapData[_inputToken][_outputToken] = _swapData;
}
/**
* Set Pendle Market to use for specific pt including relevant metadata
*
* @param _pt Address of the Pendle Principal Token
* @param _sy Address of the corresponding Standardized Yield Token
* @param _underlying Address of the underlying token to redeem to
* @param _market Address of the Pendle Market to use for swapping between pt and sy
* @param _exchangeRateFactor Factor to multiply the exchange rate when supplying to Pendle Market
*/functionsetPendleMarket(
IPendlePrincipalToken _pt,
IPendleStandardizedYield _sy,
address _underlying,
IPendleMarketV3 _market,
uint256 _exchangeRateFactor
) externalonlyOwner{
pendleMarkets[_pt] = _market;
pendleMarketData[_market] = PendleMarketData({
pt: _pt,
sy: _sy,
underlying: _underlying,
exchangeRateFactor: _exchangeRateFactor
});
}
/**
* Callback method that is called by Pendle Market during the swap to request input token
*
* @param _ptToAccount Swap balance of pt token (negative -> swapping pt to sy)
* @param _syToAccount Swap balance of sy token (negative -> swapping sy to pt)
* @param _data Arbitrary data passed by Pendle Market (not used)
*/functionswapCallback(int256 _ptToAccount, int256 _syToAccount, bytescalldata _data) external{
PendleMarketData storage marketData = pendleMarketData[IPendleMarketV3(msg.sender)];
require(address(marketData.sy) !=address(0), "ISC");
if (_ptToAccount <0) {
uint256 ptAmount =uint256(-_ptToAccount);
marketData.pt.transfer(msg.sender, ptAmount);
} elseif (_syToAccount <0) {
uint256 syAmount =uint256(-_syToAccount);
// Withdraw necessary ETH, if deposit size is enough to move the oracle, then the exchange rate will not be// valid for computing the amount of ETH to withdraw, so increase by exchangeRateFactoruint256 ethAmount = syAmount.mul(marketData.sy.exchangeRate()).div(1ether);
uint256 syAmountPreview = marketData.sy.previewDeposit(address(0), ethAmount);
if (syAmountPreview < syAmount) {
ethAmount = ethAmount * marketData.exchangeRateFactor /1ether;
}
// Special handling for agETHif (marketData.underlying ==address(agETH)) {
rsEthAdapter.getRSETHWithETH{value: ethAmount}("");
uint256 agEthAmount = agETH.balanceOf(address(this));
marketData.sy.deposit(address(this), address(agETH), agEthAmount, 0);
} else {
marketData.sy.deposit{ value: ethAmount }(address(this), address(0), ethAmount, 0);
}
marketData.sy.transfer(msg.sender, syAmount);
} else {
revert("Invalid callback");
}
}
/* ============ Internal ============ *//**
* @dev Issue exact amount of SetToken from ETH
*
*/function_issueExactSetFromEth(
ISetToken _setToken,
uint256 _amountSetToken,
DEXAdapterV3.SwapData[] memory _swapDataEthToComponent
) internalreturns (uint256) {
(address[] memory components, uint256[] memory positions, ) = IDebtIssuanceModule(
issuanceModule
).getRequiredComponentIssuanceUnits(_setToken, _amountSetToken);
uint256 ethBalanceBefore =address(this).balance;
for (uint256 i =0; i < components.length; i++) {
_depositIntoComponent(components[i], positions[i], _swapDataEthToComponent[i]);
}
issuanceModule.issue(_setToken, _amountSetToken, msg.sender);
return ethBalanceBefore.sub(address(this).balance);
}
/**
* @dev Redeem exact amount of SetToken for ETH
*
*/function_redeemExactSetForETH(
ISetToken _setToken,
uint256 _amountSetToken,
uint256 _minETHOut,
DEXAdapterV3.SwapData[] memory _swapDataComponentToEth
) internalreturns (uint256) {
uint256 ethBalanceBefore =address(this).balance;
_setToken.safeTransferFrom(msg.sender, address(this), _amountSetToken);
issuanceModule.redeem(_setToken, _amountSetToken, address(this));
(address[] memory components, uint256[] memory positions, ) = IDebtIssuanceModule(
issuanceModule
).getRequiredComponentRedemptionUnits(_setToken, _amountSetToken);
for (uint256 i =0; i < components.length; i++) {
_withdrawFromComponent(components[i], positions[i], _swapDataComponentToEth[i]);
}
returnaddress(this).balance.sub(ethBalanceBefore);
}
/**
* @dev Deposit ETH into given component
*
*/function_depositIntoComponent(address _component,
uint256 _amount,
DEXAdapterV3.SwapData memory _swapData
) internal{
if(_swapData.exchange != DEXAdapterV3.Exchange.None) {
_swapEthForExactToken(_component, _amount, _swapData);
return;
}
if (_isInstadapp(_component)) {
_depositIntoInstadapp(IERC4626(_component), _amount);
return;
}
IPendleStandardizedYield syToken = _getSyToken(IPendlePrincipalToken(_component));
if (syToken != IPendleStandardizedYield(address(0))) {
_depositIntoPendle(IPendlePrincipalToken(_component), _amount, syToken);
return;
}
if (IERC20(_component) == acrossToken) {
_depositIntoAcross(_amount);
return;
}
if (_component == dexAdapter.weth) {
IWETH(dexAdapter.weth).deposit{ value: _amount }();
return;
}
if (erc4626Components[_component]) {
uint256 assetAmount = IERC4626(_component).previewMint(_amount);
address asset = IERC4626(_component).asset();
_swapEthForExactToken(asset, assetAmount, swapData[DEXAdapterV3.ETH_ADDRESS][asset]);
IERC4626(_component).mint(_amount, address(this));
return;
}
revert("Missing Swapdata for non-standard component");
}
/**
* @dev Withdraw ETH from given component
*
*/function_withdrawFromComponent(address _component,
uint256 _amount,
DEXAdapterV3.SwapData memory _swapData
) internal{
if(_swapData.exchange != DEXAdapterV3.Exchange.None) {
require(_swapData.path.length>1, "zero length swap path");
require(_swapData.path[0] == _component, "Invalid input token");
require(_swapData.path[_swapData.path.length-1] == DEXAdapterV3.ETH_ADDRESS || _swapData.path[_swapData.path.length-1] == dexAdapter.weth, "Invalid output token");
uint256 ethReceived = dexAdapter.swapExactTokensForTokens(_amount, 0, _swapData);
if(_swapData.path[_swapData.path.length-1] == dexAdapter.weth) {
IWETH(dexAdapter.weth).withdraw(ethReceived);
}
return;
}
if (_isInstadapp(_component)) {
_withdrawFromInstadapp(IERC4626(_component), _amount);
return;
}
IPendleMarketV3 market = pendleMarkets[IPendlePrincipalToken(_component)];
if (market != IPendleMarketV3(address(0))) {
_withdrawFromPendle(IPendlePrincipalToken(_component), _amount, market);
return;
}
if (IERC20(_component) == acrossToken) {
_withdrawFromAcross(_amount);
return;
}
if (_component == dexAdapter.weth) {
IWETH(dexAdapter.weth).withdraw(_amount);
return;
}
if (erc4626Components[_component]) {
address asset = IERC4626(_component).asset();
uint256 assetAmount = IERC4626(_component).redeem(_amount, address(this), address(this));
_swapExactTokenForEth(IERC20(asset), assetAmount, swapData[asset][DEXAdapterV3.ETH_ADDRESS]);
return;
}
revert("Missing Swapdata for non-standard component");
}
/**
* @dev Deposit eth into steth and then into instadapp vault
*
*/function_depositIntoInstadapp(IERC4626 _vault, uint256 _amount) internal{
uint256 stETHAmount = _vault.previewMint(_amount);
_depositIntoLido(stETHAmount);
_vault.mint(_amount, address(this));
}
/**
* @dev Deposit eth into steth
*
*/function_depositIntoLido(uint256 _amount) internal{
stETH.submit{ value: _amount }(address(0));
}
/**
* @dev Withdraw steth from instadapp vault and then swap to eth
* @dev Requires the respective swap data (stETH -> ETH) to be set
*
*/function_withdrawFromInstadapp(IERC4626 _vault, uint256 _amount) internal{
uint256 stETHAmount = _vault.redeem(_amount, address(this), address(this));
_swapExactTokensForTokens(stETHAmount, address(stETH), address(0));
}
/**
* @dev Check if given component is the Instadapp vault
*
*/function_isInstadapp(address _token) internalpurereturns (bool) {
return _token ==0xA0D3707c569ff8C87FA923d3823eC5D81c98Be78;
}
/**
* @dev Get Sy token for given pt token
* @dev Also functions as check if given component is a Pendle Principal Token
*
*/function_getSyToken(
IPendlePrincipalToken _pt
) internalviewreturns (IPendleStandardizedYield) {
return pendleMarketData[pendleMarkets[_pt]].sy;
}
/**
* @dev Initiate deposit into Pendle by swapping pt for sy
* @dev Deposit from eth to sy is done in swapCallback
*/function_depositIntoPendle(
IPendlePrincipalToken _pt,
uint256 _ptAmount,
IPendleStandardizedYield _sy
) internal{
// Adding random bytes here since PendleMarket will not call back if data is empty
IPendleMarketV3(pendleMarkets[_pt]).swapSyForExactPt(address(this), _ptAmount, bytes("a"));
}
/**
* @dev Obtain across lp tokens by adding eth liquidity into the across pool
*/function_depositIntoAcross(uint256 _acrossLpAmount) internal{
uint256 ethAmount = acrossPool
.exchangeRateCurrent(dexAdapter.weth)
.mul(_acrossLpAmount)
.div(1e18)
.add(ROUNDING_ERROR);
acrossPool.addLiquidity{ value: ethAmount }(dexAdapter.weth, ethAmount);
}
/**
* @dev Withdraw eth by removing liquidity from across pool
*/function_withdrawFromAcross(uint256 _acrossLpAmount) internal{
acrossPool.removeLiquidity(dexAdapter.weth, _acrossLpAmount, true);
}
/**
* @dev Withdraw from Pendle by swapping pt for sy, redeeming sy for underlying and swapping underlying to eth
*/function_withdrawFromPendle(
IPendlePrincipalToken _pt,
uint256 _ptAmount,
IPendleMarketV3 _pendleMarket
) internal{
// Adding random bytes here since PendleMarket will not call back if data is empty
(uint256 syAmount, ) = _pendleMarket.swapExactPtForSy(address(this), _ptAmount, bytes("a"));
PendleMarketData storage data = pendleMarketData[_pendleMarket];
uint256 amountUnderlying = data.sy.redeem(
address(this),
syAmount,
data.underlying,
0,
false
);
_swapExactTokensForTokens(amountUnderlying, data.underlying, address(0));
IWETH(dexAdapter.weth).withdraw(IERC20(dexAdapter.weth).balanceOf(address(this)));
}
/**
* @dev Swap exact amount of input token for output token using configured swap data
*/function_swapExactTokensForTokens(uint256 _amountIn,
address _inputToken,
address _outputToken
) internalreturns (uint256) {
dexAdapter.swapExactTokensForTokens(_amountIn, 0, swapData[_inputToken][_outputToken]);
}
/**
* @dev Convert ETH to specified token, either swapping or simply depositing if outputToken is WETH
*/function_swapFromEthToToken(
IERC20 _outputToken,
uint256 _ethAmount,
DEXAdapterV3.SwapData memory _swapDataEthToOutputToken
) internalreturns(uint256 outputTokenAmount) {
if(address(_outputToken) ==address(dexAdapter.weth)) {
outputTokenAmount = _ethAmount;
IWETH(dexAdapter.weth).deposit{value: _ethAmount}();
} else {
if(_swapDataEthToOutputToken.path[0] == dexAdapter.weth) {
IWETH(dexAdapter.weth).deposit{value: _ethAmount}();
}
outputTokenAmount = dexAdapter.swapExactTokensForTokens(
_ethAmount,
0,
_swapDataEthToOutputToken
);
}
}
/**
* @dev Convert specified token to ETH, either swapping or simply withdrawing if inputToken is WETH
*/function_swapExactTokenForEth(
IERC20 _inputToken,
uint256 _inputTokenAmount,
DEXAdapterV3.SwapData memory _swapDataInputTokenToEth
) internalreturns (uint256 ethAmount) {
if(address(_inputToken) == dexAdapter.weth) {
ethAmount = _inputTokenAmount;
IWETH(dexAdapter.weth).withdraw(ethAmount);
} else {
ethAmount = dexAdapter.swapExactTokensForTokens(
_inputTokenAmount,
0,
_swapDataInputTokenToEth
);
if(_swapDataInputTokenToEth.path[_swapDataInputTokenToEth.path.length-1] == dexAdapter.weth) {
IWETH(dexAdapter.weth).withdraw(ethAmount);
}
}
}
function_swapEthForExactToken(address _token, uint256 _amount, DEXAdapterV3.SwapData memory _swapData) internal{
if(_token == dexAdapter.weth) {
IWETH(dexAdapter.weth).deposit{value: _amount}();
return;
}
require(_swapData.path.length>1, "zero length swap path");
require(_swapData.path[0] == DEXAdapterV3.ETH_ADDRESS || _swapData.path[0] == dexAdapter.weth, "Invalid input token");
require(_swapData.path[_swapData.path.length-1] == _token, "Invalid output token");
if(_swapData.path[0] == dexAdapter.weth) {
uint256 balanceBefore = IWETH(dexAdapter.weth).balanceOf(address(this));
IWETH(dexAdapter.weth).deposit{value: address(this).balance}();
dexAdapter.swapTokensForExactTokens(_amount, IWETH(dexAdapter.weth).balanceOf(address(this)), _swapData);
IWETH(dexAdapter.weth).withdraw(IWETH(dexAdapter.weth).balanceOf(address(this)).sub(balanceBefore));
}
else {
dexAdapter.swapTokensForExactTokens(_amount, address(this).balance, _swapData);
}
}
}
/*
Copyright 2020 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;interfaceIController{
functionaddSet(address _setToken) external;
functionfeeRecipient() externalviewreturns(address);
functiongetModuleFee(address _module, uint256 _feeType) externalviewreturns(uint256);
functionisModule(address _module) externalviewreturns(bool);
functionisSet(address _setToken) externalviewreturns(bool);
functionisSystemContract(address _contractAddress) externalviewreturns (bool);
functionisResource(address _resource) externalviewreturns(bool);
functionresourceId(uint256 _id) externalviewreturns(address);
functionowner() externalviewreturns(address);
functionaddFactory(address _factory) external;
functionaddModule(address _module) external;
}
Contract Source Code
File 7 of 32: ICurveAddressProvider.sol
/*
Copyright 2022 Index Cooperative
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;// Implementation: https://etherscan.io/address/0x0000000022d53366457f9d5e68ec105046fc4383#readContractinterfaceICurveAddressProvider{
functionget_registry() externalviewreturns(address);
functionget_address(uint256 _id) externalviewreturns(address);
}
Contract Source Code
File 8 of 32: ICurveCalculator.sol
/*
Copyright 2022 Index Cooperative
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;// Implementation: https://etherscan.io/address/0xc1DB00a8E5Ef7bfa476395cdbcc98235477cDE4E#readContractinterfaceICurveCalculator{
functionget_dx(int128 n_coins,
uint256[8] memory balances,
uint256 amp,
uint256 fee,
uint256[8] memory rates,
uint256[8] memory precisions,
bool underlying,
int128 i,
int128 j,
uint256 dy
) externalviewreturns(uint256);
functionget_dy(int128 n_coins,
uint256[8] memory balances,
uint256 amp,
uint256 fee,
uint256[8] memory rates,
uint256[8] memory precisions,
bool underlying,
int128 i,
int128 j,
uint256 dx
) externalviewreturns(uint256);
}
Contract Source Code
File 9 of 32: ICurvePool.sol
/*
Copyright 2022 Index Cooperative
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;// Implementation: https://etherscan.io/address/0x8e764bE4288B842791989DB5b8ec067279829809#writeContractinterfaceICurvePool{
functionexchange(int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) externalpayablereturns (uint256);
functionget_dy(int128 i,
int128 j,
uint256 dx
) externalviewreturns (uint256);
}
Contract Source Code
File 10 of 32: ICurvePoolRegistry.sol
/*
Copyright 2022 Index Cooperative
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;// Implementation: https://etherscan.io/address/0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5#readContractinterfaceICurvePoolRegistry{
// amplification factorfunctionget_A(address _pool) externalviewreturns(uint256);
functionget_balances(address _pool) externalviewreturns(uint256[8] memory);
functionget_coins(address _pool) externalviewreturns(address[8] memory);
functionget_coin_indices(address _pool, address _from, address _to) externalviewreturns(int128, int128, bool);
functionget_decimals(address _pool) externalviewreturns(uint256[8] memory);
functionget_n_coins(address _pool) externalviewreturns(uint256[2] memory);
functionget_fees(address _pool) externalviewreturns(uint256[2] memory);
functionget_rates(address _pool) externalviewreturns(uint256[8] memory);
}
Contract Source Code
File 11 of 32: IDebtIssuanceModule.sol
/*
Copyright 2020 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity >=0.6.10;import { ISetToken } from"./ISetToken.sol";
import { IManagerIssuanceHook } from"./IManagerIssuanceHook.sol";
interfaceIDebtIssuanceModule{
functiongetRequiredComponentIssuanceUnits(
ISetToken _setToken,
uint256 _quantity
) externalviewreturns (address[] memory, uint256[] memory, uint256[] memory);
functiongetRequiredComponentRedemptionUnits(
ISetToken _setToken,
uint256 _quantity
) externalviewreturns (address[] memory, uint256[] memory, uint256[] memory);
functionissue(ISetToken _setToken, uint256 _quantity, address _to) external;
functionredeem(ISetToken _token, uint256 _quantity, address _to) external;
functioninitialize(
ISetToken _setToken,
uint256 _maxManagerFee,
uint256 _managerIssueFee,
uint256 _managerRedeemFee,
address _feeRecipient,
IManagerIssuanceHook _managerIssuanceHook
) external;
}
Contract Source Code
File 12 of 32: IERC20.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransfer(address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/functionallowance(address owner, address spender) externalviewreturns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/functionapprove(address spender, uint256 amount) externalreturns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/functiontransferFrom(address sender, address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
}
/*
Copyright 2020 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;import { ISetToken } from"./ISetToken.sol";
interfaceIManagerIssuanceHook{
functioninvokePreIssueHook(ISetToken _setToken, uint256 _issueQuantity, address _sender, address _to) external;
functioninvokePreRedeemHook(ISetToken _setToken, uint256 _redeemQuantity, address _sender, address _to) external;
}
// SPDX-License-Identifier: GPL-2.0-or-laterpragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;/// @title Quoter Interface/// @notice Supports quoting the calculated amounts from exact input or exact output swaps/// @dev These functions are not marked view because they rely on calling non-view functions and reverting/// to compute the result. They are also not gas efficient and should not be called on-chain.interfaceIQuoter{
/// @notice Returns the amount out received for a given exact input swap without executing the swap/// @param path The path of the swap, i.e. each token pair and the pool fee/// @param amountIn The amount of the first token to swap/// @return amountOut The amount of the last token that would be receivedfunctionquoteExactInput(bytesmemory path, uint256 amountIn) externalreturns (uint256 amountOut);
/// @notice Returns the amount out received for a given exact input but for a swap of a single pool/// @param tokenIn The token being swapped in/// @param tokenOut The token being swapped out/// @param fee The fee of the token pool to consider for the pair/// @param amountIn The desired input amount/// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap/// @return amountOut The amount of `tokenOut` that would be receivedfunctionquoteExactInputSingle(address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountIn,
uint160 sqrtPriceLimitX96
) externalreturns (uint256 amountOut);
/// @notice Returns the amount in required for a given exact output swap without executing the swap/// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order/// @param amountOut The amount of the last token to receive/// @return amountIn The amount of first token required to be paidfunctionquoteExactOutput(bytesmemory path, uint256 amountOut) externalreturns (uint256 amountIn);
/// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool/// @param tokenIn The token being swapped in/// @param tokenOut The token being swapped out/// @param fee The fee of the token pool to consider for the pair/// @param amountOut The desired output amount/// @param sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap/// @return amountIn The amount required as the input for the swap in order to receive `amountOut`functionquoteExactOutputSingle(address tokenIn,
address tokenOut,
uint24 fee,
uint256 amountOut,
uint160 sqrtPriceLimitX96
) externalreturns (uint256 amountIn);
}
// SPDX-License-Identifier: Apache License, Version 2.0pragmasolidity 0.6.10;pragmaexperimental"ABIEncoderV2";import { IERC20 } from"@openzeppelin/contracts/token/ERC20/IERC20.sol";
/**
* @title ISetToken
* @author Set Protocol
*
* Interface for operating with SetTokens.
*/interfaceISetTokenisIERC20{
/* ============ Enums ============ */enumModuleState {
NONE,
PENDING,
INITIALIZED
}
/* ============ Structs ============ *//**
* The base definition of a SetToken Position
*
* @param component Address of token in the Position
* @param module If not in default state, the address of associated module
* @param unit Each unit is the # of components per 10^18 of a SetToken
* @param positionState Position ENUM. Default is 0; External is 1
* @param data Arbitrary data
*/structPosition {
address component;
address module;
int256 unit;
uint8 positionState;
bytes data;
}
/**
* A struct that stores a component's cash position details and external positions
* This data structure allows O(1) access to a component's cash position units and
* virtual units.
*
* @param virtualUnit Virtual value of a component's DEFAULT position. Stored as virtual for efficiency
* updating all units at once via the position multiplier. Virtual units are achieved
* by dividing a "real" value by the "positionMultiplier"
* @param componentIndex
* @param externalPositionModules List of external modules attached to each external position. Each module
* maps to an external position
* @param externalPositions Mapping of module => ExternalPosition struct for a given component
*/structComponentPosition {
int256 virtualUnit;
address[] externalPositionModules;
mapping(address=> ExternalPosition) externalPositions;
}
/**
* A struct that stores a component's external position details including virtual unit and any
* auxiliary data.
*
* @param virtualUnit Virtual value of a component's EXTERNAL position.
* @param data Arbitrary data
*/structExternalPosition {
int256 virtualUnit;
bytes data;
}
/* ============ Functions ============ */functioncontroller() externalviewreturns (address);
functionaddComponent(address _component) external;
functionremoveComponent(address _component) external;
functioneditDefaultPositionUnit(address _component, int256 _realUnit) external;
functionaddExternalPositionModule(address _component, address _positionModule) external;
functionremoveExternalPositionModule(address _component, address _positionModule) external;
functioneditExternalPositionUnit(address _component, address _positionModule, int256 _realUnit) external;
functioneditExternalPositionData(address _component, address _positionModule, bytescalldata _data) external;
functioninvoke(address _target, uint256 _value, bytescalldata _data) externalreturns(bytesmemory);
functioneditPositionMultiplier(int256 _newMultiplier) external;
functionmint(address _account, uint256 _quantity) external;
functionburn(address _account, uint256 _quantity) external;
functionlock() external;
functionunlock() external;
functionaddModule(address _module) external;
functionremoveModule(address _module) external;
functioninitializeModule() external;
functionsetManager(address _manager) external;
functionmanager() externalviewreturns (address);
functionmoduleStates(address _module) externalviewreturns (ModuleState);
functiongetModules() externalviewreturns (address[] memory);
functiongetDefaultPositionRealUnit(address _component) externalviewreturns(int256);
functiongetExternalPositionRealUnit(address _component, address _positionModule) externalviewreturns(int256);
functiongetComponents() externalviewreturns(address[] memory);
functiongetExternalPositionModules(address _component) externalviewreturns(address[] memory);
functiongetExternalPositionData(address _component, address _positionModule) externalviewreturns(bytesmemory);
functionisExternalPositionModule(address _component, address _module) externalviewreturns(bool);
functionisComponent(address _component) externalviewreturns(bool);
functionpositionMultiplier() externalviewreturns (int256);
functiongetPositions() externalviewreturns (Position[] memory);
functiongetTotalComponentRealUnits(address _component) externalviewreturns(int256);
functionisInitializedModule(address _module) externalviewreturns(bool);
functionisPendingModule(address _module) externalviewreturns(bool);
functionisLocked() externalviewreturns (bool);
}
// SPDX-License-Identifier: GPL-3.0-or-later// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License// along with this program. If not, see <http://www.gnu.org/licenses/>.pragmasolidity >=0.6.10 <0.9.0;pragmaexperimentalABIEncoderV2;import {IERC20} from"@openzeppelin/contracts/token/ERC20/IERC20.sol";
interfaceIFlashLoanRecipient{
/**
* @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
*
* At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
* call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
* Vault, or else the entire flash loan will revert.
*
* `userData` is the same value passed in the `IVault.flashLoan` call.
*/functionreceiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytesmemory userData
) external;
}
/**
* Stripped down interface of IVault.
* https://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/vault/IVault.sol
*/interfaceIVault{
// Swaps//// Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,// they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be// aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.//// The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.// In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),// and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').// More complex swaps, such as one token in to multiple tokens out can be achieved by batching together// individual swaps.//// There are two swap kinds:// - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the// `onSwap` hook) the amount of tokens out (to send to the recipient).// - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines// (via the `onSwap` hook) the amount of tokens in (to receive from the sender).//// Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with// the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated// tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended// swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at// the final intended token.//// In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal// Balance) after all individual swaps have been completed, and the net token balance change computed. This makes// certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost// much less gas than they would otherwise.//// It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple// Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only// updating the Pool's internal accounting).//// To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token// involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the// minimum amount of tokens to receive (by passing a negative value) is specified.//// Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after// this point in time (e.g. if the transaction failed to be included in a block promptly).//// If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do// the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be// passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the// same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).//// Finally, Internal Balance can be used when either sending or receiving tokens.enumSwapKind {
GIVEN_IN,
GIVEN_OUT
}
/**
* @dev Performs a swap with a single Pool.
*
* If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
* taken from the Pool, which must be greater than or equal to `limit`.
*
* If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
* sent to the Pool, which must be less than or equal to `limit`.
*
* Internal Balance usage and the recipient are determined by the `funds` struct.
*
* Emits a `Swap` event.
*/functionswap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) externalpayablereturns (uint256);
/**
* @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
* the `kind` value.
*
* `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
* Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/structSingleSwap {
bytes32 poolId;
SwapKind kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
/**
* @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
* the amount of tokens sent to or received from the Pool, depending on the `kind` value.
*
* Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
* Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
* the same index in the `assets` array.
*
* Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
* Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
* `amountOut` depending on the swap kind.
*
* Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
* of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
* the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
*
* The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
* or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
* out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
* or unwrapped from WETH by the Vault.
*
* Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
* the minimum or maximum amount of each token the vault is allowed to transfer.
*
* `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
* equivalent `swap` call.
*
* Emits `Swap` events.
*/functionbatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
address[] memory assets,
FundManagement memory funds,
int256[] memory limits,
uint256 deadline
) externalpayablereturns (int256[] memory);
/**
* @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
* `assets` array passed to that function, and ETH assets are converted to WETH.
*
* If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
* from the previous swap, depending on the swap kind.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/structBatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
/**
* @dev Emitted for each individual swap performed by `swap` or `batchSwap`.
*/eventSwap(bytes32indexed poolId,
IERC20 indexed tokenIn,
IERC20 indexed tokenOut,
uint256 amountIn,
uint256 amountOut
);
/**
* @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
* `recipient` account.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
* transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
* must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
* `joinPool`.
*
* If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
* transferred. This matches the behavior of `exitPool`.
*
* Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
* revert.
*/structFundManagement {
address sender;
bool fromInternalBalance;
addresspayable recipient;
bool toInternalBalance;
}
/**
* @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be
* simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result.
*
* Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH)
* the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it
* receives are the same that an equivalent `batchSwap` call would receive.
*
* Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct.
* This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens,
* approve them for the Vault, or even know a user's address.
*
* Note that this function is not 'view' (due to implementation details): the client code must explicitly execute
* eth_call instead of eth_sendTransaction.
*/functionqueryBatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
address[] memory assets,
FundManagement memory funds
) externalreturns (int256[] memory assetDeltas);
// Flash Loans/**
* @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
* and then reverting unless the tokens plus a proportional protocol fee have been returned.
*
* The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
* for each token contract. `tokens` must be sorted in ascending order.
*
* The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
* `receiveFlashLoan` call.
*
* Emits `FlashLoan` events.
*/functionflashLoan(
IFlashLoanRecipient recipient,
address[] memory tokens,
uint256[] memory amounts,
bytesmemory userData
) external;
/**
* @dev Emitted for each individual flash loan performed by `flashLoan`.
*/eventFlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount);
}
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;import"../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor () internal{
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/functionrenounceOwnership() publicvirtualonlyOwner{
emit OwnershipTransferred(_owner, address(0));
_owner =address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
Contract Source Code
File 28 of 32: PreciseUnitMath.sol
/*
Copyright 2020 Set Labs Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache License, Version 2.0
*/pragmasolidity 0.6.10;pragmaexperimentalABIEncoderV2;import { SafeMath } from"@openzeppelin/contracts/math/SafeMath.sol";
import { SignedSafeMath } from"@openzeppelin/contracts/math/SignedSafeMath.sol";
/**
* @title PreciseUnitMath
* @author Set Protocol
*
* Arithmetic for fixed-point numbers with 18 decimals of precision. Some functions taken from
* dYdX's BaseMath library.
*
* CHANGELOG:
* - 9/21/20: Added safePower function
*/libraryPreciseUnitMath{
usingSafeMathforuint256;
usingSignedSafeMathforint256;
// The number One in precise units.uint256constantinternal PRECISE_UNIT =10**18;
int256constantinternal PRECISE_UNIT_INT =10**18;
// Max unsigned integer valueuint256constantinternal MAX_UINT_256 =type(uint256).max;
// Max and min signed integer valueint256constantinternal MAX_INT_256 =type(int256).max;
int256constantinternal MIN_INT_256 =type(int256).min;
/**
* @dev Getter function since constants can't be read directly from libraries.
*/functionpreciseUnit() internalpurereturns (uint256) {
return PRECISE_UNIT;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/functionpreciseUnitInt() internalpurereturns (int256) {
return PRECISE_UNIT_INT;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/functionmaxUint256() internalpurereturns (uint256) {
return MAX_UINT_256;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/functionmaxInt256() internalpurereturns (int256) {
return MAX_INT_256;
}
/**
* @dev Getter function since constants can't be read directly from libraries.
*/functionminInt256() internalpurereturns (int256) {
return MIN_INT_256;
}
/**
* @dev Multiplies value a by value b (result is rounded down). It's assumed that the value b is the significand
* of a number with 18 decimals precision.
*/functionpreciseMul(uint256 a, uint256 b) internalpurereturns (uint256) {
return a.mul(b).div(PRECISE_UNIT);
}
/**
* @dev Multiplies value a by value b (result is rounded towards zero). It's assumed that the value b is the
* significand of a number with 18 decimals precision.
*/functionpreciseMul(int256 a, int256 b) internalpurereturns (int256) {
return a.mul(b).div(PRECISE_UNIT_INT);
}
/**
* @dev Multiplies value a by value b (result is rounded up). It's assumed that the value b is the significand
* of a number with 18 decimals precision.
*/functionpreciseMulCeil(uint256 a, uint256 b) internalpurereturns (uint256) {
if (a ==0|| b ==0) {
return0;
}
return a.mul(b).sub(1).div(PRECISE_UNIT).add(1);
}
/**
* @dev Divides value a by value b (result is rounded down).
*/functionpreciseDiv(uint256 a, uint256 b) internalpurereturns (uint256) {
return a.mul(PRECISE_UNIT).div(b);
}
/**
* @dev Divides value a by value b (result is rounded towards 0).
*/functionpreciseDiv(int256 a, int256 b) internalpurereturns (int256) {
return a.mul(PRECISE_UNIT_INT).div(b);
}
/**
* @dev Divides value a by value b (result is rounded up or away from 0).
*/functionpreciseDivCeil(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b !=0, "Cant divide by 0");
return a >0 ? a.mul(PRECISE_UNIT).sub(1).div(b).add(1) : 0;
}
/**
* @dev Divides value a by value b (result is rounded down - positive numbers toward 0 and negative away from 0).
*/functiondivDown(int256 a, int256 b) internalpurereturns (int256) {
require(b !=0, "Cant divide by 0");
require(a != MIN_INT_256 || b !=-1, "Invalid input");
int256 result = a.div(b);
if (a ^ b <0&& a % b !=0) {
result -=1;
}
return result;
}
/**
* @dev Multiplies value a by value b where rounding is towards the lesser number.
* (positive values are rounded towards zero and negative values are rounded away from 0).
*/functionconservativePreciseMul(int256 a, int256 b) internalpurereturns (int256) {
return divDown(a.mul(b), PRECISE_UNIT_INT);
}
/**
* @dev Divides value a by value b where rounding is towards the lesser number.
* (positive values are rounded towards zero and negative values are rounded away from 0).
*/functionconservativePreciseDiv(int256 a, int256 b) internalpurereturns (int256) {
return divDown(a.mul(PRECISE_UNIT_INT), b);
}
/**
* @dev Performs the power on a specified value, reverts on overflow.
*/functionsafePower(uint256 a,
uint256 pow
)
internalpurereturns (uint256)
{
require(a >0, "Value must be positive");
uint256 result =1;
for (uint256 i =0; i < pow; i++){
uint256 previousResult = result;
// Using safemath multiplication prevents overflows
result = previousResult.mul(a);
}
return result;
}
}
Contract Source Code
File 29 of 32: ReentrancyGuard.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor () internal{
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
// On the first call to nonReentrant, _notEntered will be truerequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
Contract Source Code
File 30 of 32: SafeERC20.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;import"./IERC20.sol";
import"../../math/SafeMath.sol";
import"../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/librarySafeERC20{
usingSafeMathforuint256;
usingAddressforaddress;
functionsafeTransfer(IERC20 token, address to, uint256 value) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
functionsafeTransferFrom(IERC20 token, addressfrom, address to, uint256 value) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/functionsafeApprove(IERC20 token, address spender, uint256 value) internal{
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'// solhint-disable-next-line max-line-lengthrequire((value ==0) || (token.allowance(address(this), spender) ==0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
functionsafeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal{
uint256 newAllowance = token.allowance(address(this), spender).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
functionsafeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal{
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/function_callOptionalReturn(IERC20 token, bytesmemory data) private{
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that// the target address contains contract code and also asserts for success in the low-level call.bytesmemory returndata =address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length>0) { // Return data is optional// solhint-disable-next-line max-line-lengthrequire(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Contract Source Code
File 31 of 32: SafeMath.sol
// SPDX-License-Identifier: MITpragmasolidity >=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.
*/librarySafeMath{
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontryAdd(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontrySub(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontryMul(uint256 a, uint256 b) internalpurereturns (bool, 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/522if (a ==0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/functiontryDiv(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
if (b ==0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/functiontryMod(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
if (b ==0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/functionadd(uint256 a, uint256 b) internalpurereturns (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.
*/functionsub(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/functionmul(uint256 a, uint256 b) internalpurereturns (uint256) {
if (a ==0) return0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting 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.
*/functiondiv(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b >0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting 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.
*/functionmod(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b >0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/functionsub(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* 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.
*/functiondiv(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b >0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* 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.
*/functionmod(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b >0, errorMessage);
return a % b;
}
}
Contract Source Code
File 32 of 32: SignedSafeMath.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;/**
* @title SignedSafeMath
* @dev Signed math operations with safety checks that revert on error.
*/librarySignedSafeMath{
int256constantprivate _INT256_MIN =-2**255;
/**
* @dev Returns the multiplication of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/functionmul(int256 a, int256 b) internalpurereturns (int256) {
// 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/522if (a ==0) {
return0;
}
require(!(a ==-1&& b == _INT256_MIN), "SignedSafeMath: multiplication overflow");
int256 c = a * b;
require(c / a == b, "SignedSafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two signed 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.
*/functiondiv(int256 a, int256 b) internalpurereturns (int256) {
require(b !=0, "SignedSafeMath: division by zero");
require(!(b ==-1&& a == _INT256_MIN), "SignedSafeMath: division overflow");
int256 c = a / b;
return c;
}
/**
* @dev Returns the subtraction of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/functionsub(int256 a, int256 b) internalpurereturns (int256) {
int256 c = a - b;
require((b >=0&& c <= a) || (b <0&& c > a), "SignedSafeMath: subtraction overflow");
return c;
}
/**
* @dev Returns the addition of two signed integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/functionadd(int256 a, int256 b) internalpurereturns (int256) {
int256 c = a + b;
require((b >=0&& c >= a) || (b <0&& c < a), "SignedSafeMath: addition overflow");
return c;
}
}