Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
RouterUtil
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import {Math} from "openzeppelin-math/Math.sol";
import {IERC20Metadata} from "openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC4626} from "openzeppelin-contracts/interfaces/IERC4626.sol";
import {IERC3156FlashLender} from "openzeppelin-contracts/interfaces/IERC3156FlashLender.sol";
import {SafeCast} from "openzeppelin-contracts/utils/math/SafeCast.sol";
import {CurvePoolUtil} from "../../libraries/CurvePoolUtil.sol";
import {ICurvePool} from "../../interfaces/ICurvePool.sol";
import {IStableSwapNG} from "../../interfaces/IStableSwapNG.sol";
import {ICurveNGPool} from "../../interfaces/ICurveNGPool.sol";
import {IPrincipalToken} from "../../interfaces/IPrincipalToken.sol";
import {Constants} from "../Constants.sol";
/**
* @title Router Util contract
* @author Spectra Finance
* @notice Provides miscellaneous utils and preview functions related to Router executions.
*/
contract RouterUtil {
using Math for uint256;
using SafeCast for uint256;
using SafeCast for int256;
error InvalidTokenIndex(uint256 i, uint256 j);
error PoolLiquidityError();
error UnsufficientAmountForFlashFee();
error ResultNotFound();
/**
* @dev Gives the spot exchange rate of token i in terms of token j. Exchange rate is in 18 decimals
* @dev To be used with Curve Cryptoswap pools
* @param _curvePool PT/IBT curve pool
* @param _i token index, either 0 or 1
* @param _j token index, either 0 or 1, must be different than _i
* @return The spot exchange rate of _i in terms of _j
*/
function spotExchangeRate(
address _curvePool,
uint256 _i,
uint256 _j
) public view returns (uint256) {
if (_i == 0 && _j == 1) {
return
CurvePoolUtil.CURVE_UNIT.mulDiv(
CurvePoolUtil.CURVE_UNIT,
ICurvePool(_curvePool).last_prices()
);
} else if (_i == 1 && _j == 0) {
return ICurvePool(_curvePool).last_prices();
} else {
revert InvalidTokenIndex(_i, _j);
}
}
/**
* @dev Gives the spot exchange rate of token i in terms of token j. Exchange rate is in 18 decimals
* @dev To be used with Curve Stableswap pools
* @param _curvePool PT/IBT curve pool
* @param _i token index, either 0 or 1
* @param _j token index, either 0 or 1, must be different than _i
* @return The spot exchange rate of _i in terms of _j
*/
function spotExchangeRateSNG(
address _curvePool,
int128 _i,
int128 _j
) public view returns (uint256) {
uint256 last_prices = IStableSwapNG(_curvePool).last_price(0);
uint256[] memory stored_rates = IStableSwapNG(_curvePool).stored_rates();
if (_i == 0 && _j == 1) {
last_prices = stored_rates[0].mulDiv(CurvePoolUtil.CURVE_UNIT, stored_rates[1]).mulDiv(
CurvePoolUtil.CURVE_UNIT,
last_prices
);
return last_prices;
} else if (_i == 1 && _j == 0) {
last_prices = last_prices.mulDiv(stored_rates[1], stored_rates[0]);
return last_prices;
} else {
revert InvalidTokenIndex(uint256(uint128(_i)), uint256(uint128(_j)));
}
}
/**
* @dev To be used with Curve Cryptoswap pools
* @dev Gives the upper bound of the interval to perform bisection search in previewFlashSwapExactIBTForYT().
* @param _inputIBTAmount amount of IBT exchanged for YT
* @param _curvePool PT/IBT curve pool
* @return The upper bound for search interval in root finding algorithms
*/
function convertIBTToYTSpot(
uint256 _inputIBTAmount,
address _curvePool
) public view returns (uint256) {
// The spot exchange rate between IBT and YT is evaluated using the tokenization equation without fees.
// This equation reads: ptRate = 1 PT + 1 YT .
address pt = ICurvePool(_curvePool).coins(1);
uint256 ibtRate = IPrincipalToken(pt).getIBTRate(); // Ray
uint256 ptRate = IPrincipalToken(pt).getPTRate(); // Ray
uint256 ptInUnderlyingRay = spotExchangeRate(_curvePool, 1, 0).mulDiv(
ibtRate,
CurvePoolUtil.CURVE_UNIT
);
if (ptInUnderlyingRay > ptRate) {
revert PoolLiquidityError();
}
uint256 ytInUnderlyingRay = ptRate - ptInUnderlyingRay;
return _inputIBTAmount.mulDiv(ibtRate, ytInUnderlyingRay);
}
/**
* @dev Returns the maximal amount of YT one can obtain with a given amount of IBT (i.e without fees or slippage).
* @dev To be used with Curve Stableswap NG pools
* @dev Gives the upper bound of the interval to perform bisection search in previewFlashSwapExactIBTForYT().
* @param _inputIBTAmount amount of IBT exchanged for YT
* @param _curvePool PT/IBT curve pool
* @return The upper bound for search interval in root finding algorithms
*/
function convertIBTToYTSpotSNG(
uint256 _inputIBTAmount,
address _curvePool
) public view returns (uint256) {
// The spot exchange rate between IBT and YT is evaluated using the tokenization equation without fees.
// This equation reads: ptRate = 1 PT + 1 YT .
address pt = ICurvePool(_curvePool).coins(1);
uint256 ibtRate = IPrincipalToken(pt).getIBTRate(); // Ray
uint256 ptRate = IPrincipalToken(pt).getPTRate(); // Ray
uint256 ptInUnderlyingRay = spotExchangeRateSNG(_curvePool, 1, 0).mulDiv(
ibtRate,
CurvePoolUtil.CURVE_UNIT
);
if (ptInUnderlyingRay > ptRate) {
revert PoolLiquidityError();
}
uint256 ytInUnderlyingRay = ptRate - ptInUnderlyingRay;
return _inputIBTAmount.mulDiv(ibtRate, ytInUnderlyingRay);
}
/* PREVIEW FUNCTIONS FOR CURVE CRYPTOSWAP POOLS
*****************************************************************************************************************/
/**
* @dev Computes the amount of IBT required to buy a given output amount of YT.
* @dev Works for both Cryptoswap
* @param _curvePool PT/IBT curve pool
* @param _outputYTAmount desired output YT token amount
* @return inputIBTAmount The amount of IBT needed for obtaining the defined amount of YT
* @return borrowedIBTAmount the quantity of IBT borrowed to execute that swap
*/
function previewFlashSwapIBTToExactYT(
address _curvePool,
uint256 _outputYTAmount
) public view returns (uint256 inputIBTAmount, uint256 borrowedIBTAmount) {
// Tokens
address pt = ICurvePool(_curvePool).coins(1);
address ibt = IPrincipalToken(pt).getIBT();
// Units and rates
uint256 ibtRate = IPrincipalToken(pt).getIBTRate(); // Ray
uint256 ptRate = IPrincipalToken(pt).getPTRate(); // Ray
// Outputs
uint256 swapPTForIBT = ICurvePool(_curvePool).get_dy(1, 0, _outputYTAmount);
// y PT:YT = (x IBT * ((UNIT - tokenizationFee) / UNIT) * ibtRate) / ptRate
// <=> x IBT = (y PT:YT * ptRate * UNIT) / (ibtRate * (UNIT - tokenizationFee))
borrowedIBTAmount = (_outputYTAmount * ptRate * Constants.UNIT).ceilDiv(
ibtRate * (Constants.UNIT - IPrincipalToken(pt).getTokenizationFee())
);
if (swapPTForIBT > borrowedIBTAmount) {
revert PoolLiquidityError();
}
inputIBTAmount =
borrowedIBTAmount +
_getFlashFee(pt, ibt, borrowedIBTAmount) -
swapPTForIBT;
}
/**
* @dev Computes the amount of IBT required to buy a given output amount of YT.
* @dev Works for both Stableswap NG pools
* @param _curvePool PT/IBT curve pool
* @param _outputYTAmount desired output YT token amount
* @return inputIBTAmount The amount of IBT needed for obtaining the defined amount of YT
* @return borrowedIBTAmount the quantity of IBT borrowed to execute that swap
*/
function previewFlashSwapIBTToExactYTSNG(
address _curvePool,
uint256 _outputYTAmount
) public view returns (uint256 inputIBTAmount, uint256 borrowedIBTAmount) {
// Tokens
address pt = ICurvePool(_curvePool).coins(1);
address ibt = IPrincipalToken(pt).getIBT();
// Units and rates
uint256 ibtRate = IPrincipalToken(pt).getIBTRate(); // Ray
uint256 ptRate = IPrincipalToken(pt).getPTRate(); // Ray
// Outputs
uint256 swapPTForIBT = IStableSwapNG(_curvePool).get_dy(1, 0, _outputYTAmount);
// y PT:YT = (x IBT * ((UNIT - tokenizationFee) / UNIT) * ibtRate) / ptRate
// <=> x IBT = (y PT:YT * ptRate * UNIT) / (ibtRate * (UNIT - tokenizationFee))
borrowedIBTAmount = (_outputYTAmount * ptRate * Constants.UNIT).ceilDiv(
ibtRate * (Constants.UNIT - IPrincipalToken(pt).getTokenizationFee())
);
if (swapPTForIBT > borrowedIBTAmount) {
revert PoolLiquidityError();
}
inputIBTAmount =
borrowedIBTAmount +
_getFlashFee(pt, ibt, borrowedIBTAmount) -
swapPTForIBT;
}
/**
* @dev Approximates the expected output amount of YT corresponding to a given input amount of IBT.
* @dev To be used with Curve Cryptoswap pools
* @dev May return an output YT amount that corresponds to an input IBT amount lower than the given _inputIBTAmount.
* @dev This function can be expensive to execute and should only be called off-chain. Avoid using it within a transaction.
* @param _curvePool PT/IBT curve pool
* @param _inputIBTAmount amount of IBT exchanged for YT
* @return ytAmount The guess of YT obtained for the given amount of IBT
* @return borrowedIBTAmount The quantity of IBT borrowed to execute that swap.
*/
function previewFlashSwapExactIBTToYT(
address _curvePool,
uint256 _inputIBTAmount
) public view returns (uint256 ytAmount, uint256 borrowedIBTAmount) {
// initial guesses
address pt = ICurvePool(_curvePool).coins(1);
uint256 x0 = IPrincipalToken(pt).previewDepositIBT(_inputIBTAmount);
uint256 x1 = convertIBTToYTSpot(_inputIBTAmount, _curvePool);
uint256 ibtUnit = getUnit(ICurvePool(_curvePool).coins(0));
// Use secant method to approximate ytAmount
for (uint256 i = 0; i < Constants.MAX_ITERATIONS_SECANT; ++i) {
if (
_delta(x0, x1).mulDiv(ibtUnit, Math.max(x0, x1)) <
ibtUnit / Constants.PRECISION_DIVISOR
) {
break;
}
(uint256 inputIBTAmount0, ) = previewFlashSwapIBTToExactYT(_curvePool, x0);
(uint256 inputIBTAmount1, ) = previewFlashSwapIBTToExactYT(_curvePool, x1);
int256 answer0 = inputIBTAmount0.toInt256() - _inputIBTAmount.toInt256();
int256 answer1 = inputIBTAmount1.toInt256() - _inputIBTAmount.toInt256();
if (answer0 == answer1) {
break;
}
// x2 = x1 - (f(x1) * (x1 - x0) / (f(x1) - f(x0)))
// x0, x1 = x1, x2
uint256 x2 = (x1.toInt256() -
((answer1 * (x1.toInt256() - x0.toInt256())) / (answer1 - answer0))).toUint256();
x0 = x1;
x1 = x2;
}
ytAmount = Math.min(x0, x1);
uint256 resInputIBTAmount;
(resInputIBTAmount, borrowedIBTAmount) = previewFlashSwapIBTToExactYT(_curvePool, ytAmount);
// Run linear search if inputIBTAmount corresponding to ytAmount is higher than requested
if (resInputIBTAmount > _inputIBTAmount) {
// linear search
uint256 sf = Constants.SCALING_FACTOR_LINEAR_SEARCH;
for (uint256 i = 0; i < Constants.MAX_ITERATIONS_LINEAR_SEARCH; ++i) {
ytAmount = ytAmount.mulDiv(sf - 1, sf);
(resInputIBTAmount, borrowedIBTAmount) = previewFlashSwapIBTToExactYT(
_curvePool,
ytAmount
);
if (resInputIBTAmount <= _inputIBTAmount) {
break;
}
}
}
// if result is still higher or too far from requested value
if (
resInputIBTAmount > _inputIBTAmount ||
_delta(_inputIBTAmount, resInputIBTAmount).mulDiv(ibtUnit, _inputIBTAmount) >
ibtUnit / Constants.PRECISION_DIVISOR
) {
revert ResultNotFound();
}
}
/**
* @dev Approximates the expected output amount of YT corresponding to a given input amount of IBT.
* @dev To be used with Curve Stableswap NG pools
* @dev May return an output YT amount that corresponds to an input IBT amount lower than the given _inputIBTAmount.
* @dev This function can be expensive to execute and should only be called off-chain. Avoid using it within a transaction.
* @param _curvePool PT/IBT curve pool
* @param _inputIBTAmount amount of IBT exchanged for YT
* @return ytAmount The guess of YT obtained for the given amount of IBT
* @return borrowedIBTAmount The quantity of IBT borrowed to execute that swap.
*/
function previewFlashSwapExactIBTToYTSNG(
address _curvePool,
uint256 _inputIBTAmount
) public view returns (uint256 ytAmount, uint256 borrowedIBTAmount) {
// initial guesses
address pt = IStableSwapNG(_curvePool).coins(1);
uint256 x0 = IPrincipalToken(pt).previewDepositIBT(_inputIBTAmount);
uint256 x1 = convertIBTToYTSpotSNG(_inputIBTAmount, _curvePool);
uint256 ibtUnit = getUnit(ICurvePool(_curvePool).coins(0));
// Use secant method to approximate ytAmount
for (uint256 i = 0; i < Constants.MAX_ITERATIONS_SECANT; ++i) {
if (
_delta(x0, x1).mulDiv(ibtUnit, Math.max(x0, x1)) <
ibtUnit / Constants.PRECISION_DIVISOR
) {
break;
}
(uint256 inputIBTAmount0, ) = previewFlashSwapIBTToExactYTSNG(_curvePool, x0);
(uint256 inputIBTAmount1, ) = previewFlashSwapIBTToExactYTSNG(_curvePool, x1);
int256 answer0 = inputIBTAmount0.toInt256() - _inputIBTAmount.toInt256();
int256 answer1 = inputIBTAmount1.toInt256() - _inputIBTAmount.toInt256();
if (answer0 == answer1) {
break;
}
// x2 = x1 - (f(x1) * (x1 - x0) / (f(x1) - f(x0)))
// x0, x1 = x1, x2
uint256 x2 = (x1.toInt256() -
((answer1 * (x1.toInt256() - x0.toInt256())) / (answer1 - answer0))).toUint256();
x0 = x1;
x1 = x2;
}
ytAmount = Math.min(x0, x1);
uint256 resInputIBTAmount;
(resInputIBTAmount, borrowedIBTAmount) = previewFlashSwapIBTToExactYTSNG(
_curvePool,
ytAmount
);
// Run linear search if inputIBTAmount corresponding to ytAmount is higher than requested
if (resInputIBTAmount > _inputIBTAmount) {
// linear search
uint256 sf = Constants.SCALING_FACTOR_LINEAR_SEARCH;
for (uint256 i = 0; i < Constants.MAX_ITERATIONS_LINEAR_SEARCH; ++i) {
ytAmount = ytAmount.mulDiv(sf - 1, sf);
(resInputIBTAmount, borrowedIBTAmount) = previewFlashSwapIBTToExactYTSNG(
_curvePool,
ytAmount
);
if (resInputIBTAmount <= _inputIBTAmount) {
break;
}
}
}
// if result is still higher or too far from requested value
if (
resInputIBTAmount > _inputIBTAmount ||
_delta(_inputIBTAmount, resInputIBTAmount).mulDiv(ibtUnit, _inputIBTAmount) >
ibtUnit / Constants.PRECISION_DIVISOR
) {
revert ResultNotFound();
}
}
/**
* @dev Given an amount of YT, previews the amount of IBT received after exchange
* @dev To be used with Curve Cryptoswap pools
* @param _curvePool PT/IBT curve pool
* @param inputYTAmount amount of YT exchanged for IBT
* @return The amount of IBT obtained for the given amount of YT
* @return The amount of IBT borrowed to execute that swap.
*/
function previewFlashSwapExactYTToIBT(
address _curvePool,
uint256 inputYTAmount
) public view returns (uint256, uint256) {
// Tokens
address pt = ICurvePool(_curvePool).coins(1);
address ibt = IPrincipalToken(pt).getIBT();
// Units and Rates
uint256 ibtRate = IPrincipalToken(pt).getIBTRate();
uint256 ptRate = IPrincipalToken(pt).getPTRate();
// Outputs
uint256 borrowedIBTAmount = CurvePoolUtil.getDx(_curvePool, 0, 1, inputYTAmount);
uint256 inputYTAmountInIBT = inputYTAmount.mulDiv(ptRate, ibtRate);
uint256 flashFee = _getFlashFee(pt, ibt, borrowedIBTAmount);
if (borrowedIBTAmount > inputYTAmountInIBT) {
revert PoolLiquidityError();
} else if (borrowedIBTAmount + flashFee > inputYTAmountInIBT) {
revert UnsufficientAmountForFlashFee();
}
uint256 outputIBTAmount = inputYTAmountInIBT - borrowedIBTAmount - flashFee;
return (outputIBTAmount, borrowedIBTAmount);
}
/**
* @dev Given an amount of YT, previews the amount of IBT received after exchange
* @dev To be used with Curve StableSwap NG pools
* @param _curvePool PT/IBT curve pool
* @param inputYTAmount amount of YT exchanged for IBT
* @return The amount of IBT obtained for the given amount of YT
* @return The amount of IBT borrowed to execute that swap.
*/
function previewFlashSwapExactYTToIBTSNG(
address _curvePool,
uint256 inputYTAmount
) public view returns (uint256, uint256) {
// Tokens
address pt = ICurvePool(_curvePool).coins(1);
address ibt = IPrincipalToken(pt).getIBT();
// Units and Rates
uint256 ibtRate = IPrincipalToken(pt).getIBTRate();
uint256 ptRate = IPrincipalToken(pt).getPTRate();
// Outputs
uint256 borrowedIBTAmount = IStableSwapNG(_curvePool).get_dx(0, 1, inputYTAmount);
uint256 inputYTAmountInIBT = inputYTAmount.mulDiv(ptRate, ibtRate);
uint256 flashFee = _getFlashFee(pt, ibt, borrowedIBTAmount);
if (borrowedIBTAmount > inputYTAmountInIBT) {
revert PoolLiquidityError();
} else if (borrowedIBTAmount + flashFee > inputYTAmountInIBT) {
revert UnsufficientAmountForFlashFee();
}
uint256 outputIBTAmount = inputYTAmountInIBT - borrowedIBTAmount - flashFee;
return (outputIBTAmount, borrowedIBTAmount);
}
/**
* @notice Given an amount of asset, previews the amount of lp tokens received after depositing in the curve pool
* @notice To be used with Curve Cryptoswap pools
* @param _curvePool address of the curve pool
* @param _assets amount of assets to deposit into the curve pool
* @return minMintAmount amount of lp tokens received
*/
function previewAddLiquidityWithAsset(
address _curvePool,
uint256 _assets
) public view returns (uint256 minMintAmount) {
address ibt = ICurvePool(_curvePool).coins(0);
uint256 ibts = IERC4626(ibt).previewDeposit(_assets);
minMintAmount = previewAddLiquidityWithIBT(_curvePool, ibts);
}
/**
* @notice Given an amount of asset, previews the amount of lp tokens received after depositing in the curve pool
* @notice To be used with Curve Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _assets amount of assets to deposit into the curve pool
* @return minMintAmount amount of lp tokens received
*/
function previewAddLiquidityWithAssetSNG(
address _curvePool,
uint256 _assets
) public view returns (uint256 minMintAmount) {
address ibt = ICurvePool(_curvePool).coins(0);
uint256 ibts = IERC4626(ibt).previewDeposit(_assets);
minMintAmount = previewAddLiquidityWithIBTSNG(_curvePool, ibts);
}
/**
* @notice Given an amount of ibt, previews the amount of lp tokens received after depositing in the curve pool
* @notice To be used with Curve Cryptoswap pools
* @param _curvePool address of the curve pool
* @param _ibts amount of ibt to deposit into the curve pool
* @return minMintAmount amount of lp tokens received
*/
function previewAddLiquidityWithIBT(
address _curvePool,
uint256 _ibts
) public view returns (uint256 minMintAmount) {
address pt = ICurvePool(_curvePool).coins(1);
uint256 ibtToDepositInPT = CurvePoolUtil.calcIBTsToTokenizeForCurvePool(
_ibts,
_curvePool,
pt
);
uint256 amount0 = _ibts - ibtToDepositInPT;
uint256 amount1 = IPrincipalToken(pt).previewDepositIBT(ibtToDepositInPT);
minMintAmount = previewAddLiquidity(_curvePool, [amount0, amount1]);
}
/**
* @notice Given an amount of ibt, previews the amount of lp tokens received after depositing in the curve pool
* @notice To be used with Curve Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _ibts amount of ibt to deposit into the curve pool
* @return minMintAmount amount of lp tokens received
*/
function previewAddLiquidityWithIBTSNG(
address _curvePool,
uint256 _ibts
) public view returns (uint256 minMintAmount) {
address pt = IStableSwapNG(_curvePool).coins(1);
uint256 ibtToDepositInPT = CurvePoolUtil.calcIBTsToTokenizeForCurvePool(
_ibts,
_curvePool,
pt
);
uint256 amount0 = _ibts - ibtToDepositInPT;
uint256 amount1 = IPrincipalToken(pt).previewDepositIBT(ibtToDepositInPT);
uint256[] memory amounts = new uint256[](2);
amounts[0] = amount0;
amounts[1] = amount1;
minMintAmount = previewAddLiquiditySNG(_curvePool, amounts);
}
/**
* @notice Given an amount of ibts and pts, previews the amount of lp tokens received after depositing in the curve pool
* @notice To be used with Curve Cryptoswap pools
* @param _curvePool address of the curve pool
* @param _amounts array of length two containing the amount of ibt and pt to deposit into the pool respectively
* @return minMintAmount amount of lp tokens received
*/
function previewAddLiquidity(
address _curvePool,
uint256[2] memory _amounts
) public view returns (uint256 minMintAmount) {
minMintAmount = CurvePoolUtil.previewAddLiquidity(_curvePool, _amounts);
}
/**
* @notice Given an amount of ibts and pts, previews the amount of lp tokens received after depositing in the curve pool
* @notice To be used with Curve Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _amounts array of length two containing the amount of ibt and pt to deposit into the pool respectively
* @return minMintAmount amount of lp tokens received
*/
function previewAddLiquiditySNG(
address _curvePool,
uint256[] memory _amounts
) public view returns (uint256 minMintAmount) {
minMintAmount = CurvePoolUtil.previewAddLiquiditySNG(_curvePool, _amounts);
}
/**
* @notice Given an amount of lp tokens, previews the amount of asset received after withdrawing from the curve pool
* @notice To be used with Curve Cryptoswap and Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @return assets amount of asset received
*/
function previewRemoveLiquidityForAsset(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256 assets) {
uint256[2] memory minAmounts = CurvePoolUtil.previewRemoveLiquidity(_curvePool, _lpAmount);
assets =
IERC4626(ICurvePool(_curvePool).coins(0)).previewRedeem(minAmounts[0]) +
IPrincipalToken(ICurvePool(_curvePool).coins(1)).previewRedeem(minAmounts[1]);
}
/**
* @notice Given an amount of lp tokens, previews the amount of asset received after withdrawing from the curve pool
* @notice To be used with Curve Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @return assets amount of asset received
*/
function previewRemoveLiquidityForAssetSNG(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256 assets) {
uint256[] memory minAmounts = CurvePoolUtil.previewRemoveLiquiditySNG(
_curvePool,
_lpAmount
);
assets =
IERC4626(ICurvePool(_curvePool).coins(0)).previewRedeem(minAmounts[0]) +
IPrincipalToken(ICurvePool(_curvePool).coins(1)).previewRedeem(minAmounts[1]);
}
/**
* @notice Given an amount of lp tokens, previews the amount of ibt received after withdrawing from the curve pool
* @notice To be used with Curve Cryptoswap
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @return ibts amount of ibt received
*/
function previewRemoveLiquidityForIBT(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256 ibts) {
uint256[2] memory minAmounts = CurvePoolUtil.previewRemoveLiquidity(_curvePool, _lpAmount);
ibts =
minAmounts[0] +
IPrincipalToken(ICurvePool(_curvePool).coins(1)).previewRedeemForIBT(minAmounts[1]);
}
/**
* @notice Given an amount of lp tokens, previews the amount of ibt received after withdrawing from the curve pool
* @notice To be used with Curve Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @return ibts amount of ibt received
*/
function previewRemoveLiquidityForIBTSNG(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256 ibts) {
uint256[] memory minAmounts = CurvePoolUtil.previewRemoveLiquiditySNG(
_curvePool,
_lpAmount
);
ibts =
minAmounts[0] +
IPrincipalToken(ICurvePool(_curvePool).coins(1)).previewRedeemForIBT(minAmounts[1]);
}
/**
* @notice Given an amount of lp tokens, previews the amount of ibt and pt received after withdrawing from the curve pool
* @notice To be used with Curve Cryptoswap and Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @return minAmounts array of length two cointaining the amount of ibt and pt received after withdrawing from the curve pool
*/
function previewRemoveLiquidity(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256[2] memory minAmounts) {
minAmounts = CurvePoolUtil.previewRemoveLiquidity(_curvePool, _lpAmount);
}
/**
* @notice Given an amount of lp tokens, previews the amount of ibt and pt received after withdrawing from the curve pool
* @notice To be used with Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @return minAmounts array of length two cointaining the amount of ibt and pt received after withdrawing from the curve pool
*/
function previewRemoveLiquiditySNG(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256[] memory minAmounts) {
minAmounts = CurvePoolUtil.previewRemoveLiquiditySNG(_curvePool, _lpAmount);
}
/**
* @notice Given an amount of lp tokens, previews the amount of token at index _i received after withdrawing from the curve pool
* @notice To be used with Curve Cryptoswap and pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @param _i Index of the token to withdraw in
* @return minAmount amount of token at index _i after withdrawing from the curve pool
*/
function previewRemoveLiquidityOneCoin(
address _curvePool,
uint256 _lpAmount,
uint256 _i
) public view returns (uint256 minAmount) {
minAmount = CurvePoolUtil.previewRemoveLiquidityOneCoin(_curvePool, _lpAmount, _i);
}
/**
* @notice Given an amount of lp tokens, previews the amount of token at index _i received after withdrawing from the curve pool
* @notice To be used with Curve Stableswap NG pools
* @param _curvePool address of the curve pool
* @param _lpAmount amount of lp tokens to withdraw from the curve pool
* @param _i Index of the token to withdraw in
* @return minAmount amount of token at index _i after withdrawing from the curve pool
*/
function previewRemoveLiquidityOneCoinSNG(
address _curvePool,
uint256 _lpAmount,
int128 _i
) public view returns (uint256 minAmount) {
minAmount = CurvePoolUtil.previewRemoveLiquidityOneCoinSNG(_curvePool, _lpAmount, _i);
}
/* PREVIEW FUNCTIONS FOR CURVE TWOCRYPTO-NG POOLS
*****************************************************************************************************************/
/**
* @dev Computes the amount of IBT required to buy a given output amount of YT.
* @param _curvePool PT/IBT curve pool
* @param _outputYTAmount desired output YT token amount
* @return inputIBTAmount The amount of IBT needed for obtaining the defined amount of YT
* @return borrowedIBTAmount the quantity of IBT borrowed to execute that swap
*/
function previewNGFlashSwapIBTToExactYT(
address _curvePool,
uint256 _outputYTAmount
) public view returns (uint256 inputIBTAmount, uint256 borrowedIBTAmount) {
return previewFlashSwapIBTToExactYT(_curvePool, _outputYTAmount);
}
/**
* @dev Approximates the expected output amount of YT corresponding to a given input amount of IBT.
* @dev May return an output YT amount that corresponds to an input IBT amount lower than the given _inputIBTAmount.
* @dev This function can be expensive to execute and should only be called off-chain. Avoid using it within a transaction.
* @param _curvePool PT/IBT curve pool
* @param _inputIBTAmount amount of IBT exchanged for YT
* @return ytAmount The guess of YT obtained for the given amount of IBT
* @return borrowedIBTAmount The quantity of IBT borrowed to execute that swap.
*/
function previewNGFlashSwapExactIBTToYT(
address _curvePool,
uint256 _inputIBTAmount
) public view returns (uint256 ytAmount, uint256 borrowedIBTAmount) {
return previewFlashSwapExactIBTToYT(_curvePool, _inputIBTAmount);
}
/**
* @dev Given an amount of YT, previews the amount of IBT received after exchange
* @param _curvePool PT/IBT curve pool
* @param inputYTAmount amount of YT exchanged for IBT
* @return The amount of IBT obtained for the given amount of YT
* @return The amount of IBT borrowed to execute that swap.
*/
function previewNGFlashSwapExactYTToIBT(
address _curvePool,
uint256 inputYTAmount
) public view returns (uint256, uint256) {
// Tokens
address pt = ICurvePool(_curvePool).coins(1);
address ibt = IPrincipalToken(pt).getIBT();
// Units and Rates
uint256 ibtRate = IPrincipalToken(pt).getIBTRate();
uint256 ptRate = IPrincipalToken(pt).getPTRate();
// Outputs
uint256 borrowedIBTAmount = ICurveNGPool(_curvePool).get_dx(0, 1, inputYTAmount);
uint256 inputYTAmountInIBT = inputYTAmount.mulDiv(ptRate, ibtRate);
uint256 flashFee = _getFlashFee(pt, ibt, borrowedIBTAmount);
if (borrowedIBTAmount > inputYTAmountInIBT) {
revert PoolLiquidityError();
} else if (borrowedIBTAmount + flashFee > inputYTAmountInIBT) {
revert UnsufficientAmountForFlashFee();
}
uint256 outputIBTAmount = inputYTAmountInIBT - borrowedIBTAmount - flashFee;
return (outputIBTAmount, borrowedIBTAmount);
}
function previewNGAddLiquidityWithAsset(
address _curvePool,
uint256 _assets
) public view returns (uint256 minMintAmount) {
address ibt = ICurveNGPool(_curvePool).coins(0);
uint256 ibts = IERC4626(ibt).previewDeposit(_assets);
minMintAmount = previewNGAddLiquidityWithIBT(_curvePool, ibts);
}
function previewNGAddLiquidityWithIBT(
address _curvePool,
uint256 _ibts
) public view returns (uint256 minMintAmount) {
address pt = ICurveNGPool(_curvePool).coins(1);
uint256 ibtToDepositInPT = CurvePoolUtil.calcIBTsToTokenizeForCurvePool(
_ibts,
_curvePool,
pt
);
uint256 amount0 = _ibts - ibtToDepositInPT;
uint256 amount1 = IPrincipalToken(pt).previewDepositIBT(ibtToDepositInPT);
minMintAmount = CurvePoolUtil.previewAddLiquidityNG(_curvePool, [amount0, amount1]);
}
function previewNGAddLiquidity(
address _curvePool,
uint256[2] memory _amounts
) public view returns (uint256 minMintAmount) {
minMintAmount = CurvePoolUtil.previewAddLiquidityNG(_curvePool, _amounts);
}
function previewNGRemoveLiquidityForAsset(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256 assets) {
uint256[2] memory minAmounts = CurvePoolUtil.previewRemoveLiquidityNG(
_curvePool,
_lpAmount
);
assets =
IERC4626(ICurveNGPool(_curvePool).coins(0)).previewRedeem(minAmounts[0]) +
IPrincipalToken(ICurveNGPool(_curvePool).coins(1)).previewRedeem(minAmounts[1]);
}
function previewNGRemoveLiquidityForIBT(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256 ibts) {
uint256[2] memory minAmounts = CurvePoolUtil.previewRemoveLiquidityNG(
_curvePool,
_lpAmount
);
ibts =
minAmounts[0] +
IPrincipalToken(ICurvePool(_curvePool).coins(1)).previewRedeemForIBT(minAmounts[1]);
}
function previewNGRemoveLiquidity(
address _curvePool,
uint256 _lpAmount
) public view returns (uint256[2] memory minAmounts) {
minAmounts = CurvePoolUtil.previewRemoveLiquidityNG(_curvePool, _lpAmount);
}
function previewNGRemoveLiquidityOneCoin(
address _curvePool,
uint256 _lpAmount,
uint256 _i
) public view returns (uint256 minAmount) {
minAmount = CurvePoolUtil.previewRemoveLiquidityOneCoinNG(_curvePool, _lpAmount, _i);
}
/* PUBLIC UTILS
*****************************************************************************************************************/
/**
* @dev Returns the unit element of the underlying asset of a PT
* @param _pt address of Principal Token
* @return The unit of underlying asset
*/
function getPTUnderlyingUnit(address _pt) external view returns (uint256) {
return getUnit(IPrincipalToken(_pt).underlying());
}
/**
* @dev Returns the unit element of the token
* @param _token address of token
* @return The unit of asset
*/
function getUnit(address _token) public view returns (uint256) {
return 10 ** IERC20Metadata(_token).decimals();
}
/* INTERNAL FUNCTIONS
*****************************************************************************************************************/
/**
* @dev Calculates the flash loan fee for borrowing a given quantity of IBT
* @param _pt address of Principal Token
* @param _ibt address of Interest Bearing Token
* @param _borrowedIBTAmount amount of Interest Bearing Tokens that have been borrowed in the flash loan
* @return The amount of fees charged for flash loan
*/
function _getFlashFee(
address _pt,
address _ibt,
uint256 _borrowedIBTAmount
) internal view returns (uint256) {
return IERC3156FlashLender(_pt).flashFee(_ibt, _borrowedIBTAmount);
}
/**
* @dev abs(a, b)
* @param a some integer
* @param b some integer
* @return The absolute value of a - b
*/
function _delta(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashBorrower.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC3156 FlashBorrower, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashBorrower {
/**
* @dev Receive a flash loan.
* @param initiator The initiator of the loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param fee The additional amount of tokens to repay.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
* @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan"
*/
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashLender.sol)
pragma solidity ^0.8.20;
import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol";
/**
* @dev Interface of the ERC3156 FlashLender, as defined in
* https://eips.ethereum.org/EIPS/eip-3156[ERC-3156].
*/
interface IERC3156FlashLender {
/**
* @dev The amount of currency available to be lended.
* @param token The loan currency.
* @return The amount of `token` that can be borrowed.
*/
function maxFlashLoan(address token) external view returns (uint256);
/**
* @dev The fee to be charged for a given loan.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @return The amount of `token` to be charged for the loan, on top of the returned principal.
*/
function flashFee(address token, uint256 amount) external view returns (uint256);
/**
* @dev Initiate a flash loan.
* @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
* @param token The loan currency.
* @param amount The amount of tokens lent.
* @param data Arbitrary data structure, intended to contain user-defined parameters.
*/
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed 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.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (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.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens 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.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (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.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
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.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// ? `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// ? `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import {IERC20Metadata} from "openzeppelin-contracts/token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface for Curve TwoCrypto-NG pool
*/
interface ICurveNGPool is IERC20Metadata {
function coins(uint256 index) external view returns (address);
function balances(uint256 index) external view returns (uint256);
function A() external view returns (uint256);
function gamma() external view returns (uint256);
function D() external view returns (uint256);
function token() external view returns (address);
function price_scale() external view returns (uint256);
function price_oracle() external view returns (uint256);
function future_A_gamma_time() external view returns (uint256);
function future_A_gamma() external view returns (uint256);
function initial_A_gamma_time() external view returns (uint256);
function initial_A_gamma() external view returns (uint256);
function fee_gamma() external view returns (uint256);
function mid_fee() external view returns (uint256);
function out_fee() external view returns (uint256);
function allowed_extra_profit() external view returns (uint256);
function adjustment_step() external view returns (uint256);
function admin_fee() external view returns (uint256);
function ma_time() external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function fee() external view returns (uint256);
function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);
function get_dx(uint256 i, uint256 j, uint256 dy) external view returns (uint256);
function last_prices() external view returns (uint256);
function calc_token_amount(
uint256[2] calldata amounts,
bool deposit
) external view returns (uint256);
function calc_withdraw_one_coin(
uint256 _token_amount,
uint256 i
) external view returns (uint256);
function exchange(uint256 i, uint256 j, uint256 dx, uint256 min_dy) external returns (uint256);
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
address receiver
) external returns (uint256);
function add_liquidity(
uint256[2] calldata amounts,
uint256 min_mint_amount
) external returns (uint256);
function add_liquidity(
uint256[2] calldata amounts,
uint256 min_mint_amount,
address receiver
) external returns (uint256);
function remove_liquidity(uint256 amount, uint256[2] calldata min_amounts) external;
function remove_liquidity(
uint256 amount,
uint256[2] calldata min_amounts,
address receiver
) external;
function remove_liquidity_one_coin(
uint256 token_amount,
uint256 i,
uint256 min_amount
) external;
function remove_liquidity_one_coin(
uint256 token_amount,
uint256 i,
uint256 min_amount,
address receiver
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
/**
* @dev Interface for Curve CryptoSwap pool
*/
interface ICurvePool {
function coins(uint256 index) external view returns (address);
function balances(uint256 index) external view returns (uint256);
function A() external view returns (uint256);
function gamma() external view returns (uint256);
function D() external view returns (uint256);
function token() external view returns (address);
function price_scale() external view returns (uint256);
function future_A_gamma_time() external view returns (uint256);
function future_A_gamma() external view returns (uint256);
function initial_A_gamma_time() external view returns (uint256);
function initial_A_gamma() external view returns (uint256);
function fee_gamma() external view returns (uint256);
function mid_fee() external view returns (uint256);
function out_fee() external view returns (uint256);
function allowed_extra_profit() external view returns (uint256);
function adjustment_step() external view returns (uint256);
function admin_fee() external view returns (uint256);
function ma_half_time() external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function fee() external view returns (uint256);
function get_dy(uint256 i, uint256 j, uint256 dx) external view returns (uint256);
function last_prices() external view returns (uint256);
function calc_token_amount(uint256[2] calldata amounts) external view returns (uint256);
function calc_withdraw_one_coin(
uint256 _token_amount,
uint256 i
) external view returns (uint256);
function exchange(
uint256 i,
uint256 j,
uint256 dx,
uint256 min_dy,
bool use_eth,
address receiver
) external returns (uint256);
function add_liquidity(
uint256[2] calldata amounts,
uint256 min_mint_amount
) external returns (uint256);
function add_liquidity(
uint256[2] calldata amounts,
uint256 min_mint_amount,
bool use_eth,
address receiver
) external returns (uint256);
function remove_liquidity(uint256 amount, uint256[2] calldata min_amounts) external;
function remove_liquidity(
uint256 amount,
uint256[2] calldata min_amounts,
bool use_eth,
address receiver
) external;
function remove_liquidity_one_coin(
uint256 token_amount,
uint256 i,
uint256 min_amount
) external;
function remove_liquidity_one_coin(
uint256 token_amount,
uint256 i,
uint256 min_amount,
bool use_eth,
address receiver
) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;
import "openzeppelin-contracts/interfaces/IERC20.sol";
import "openzeppelin-contracts/interfaces/IERC20Metadata.sol";
import "openzeppelin-contracts/interfaces/IERC3156FlashLender.sol";
interface IPrincipalToken is IERC20, IERC20Metadata, IERC3156FlashLender {
/* ERRORS
*****************************************************************************************************************/
error InvalidDecimals();
error BeaconNotSet();
error PTExpired();
error PTNotExpired();
error RateError();
error AddressError();
error UnauthorizedCaller();
error RatesAtExpiryAlreadyStored();
error ERC5143SlippageProtectionFailed();
error InsufficientBalance();
error FlashLoanExceedsMaxAmount();
error FlashLoanCallbackFailed();
error NoRewardsProxy();
error ClaimRewardsFailed();
/* Functions
*****************************************************************************************************************/
function initialize(address _ibt, uint256 _duration, address initialAuthority) external;
/**
* @notice Toggle Pause
* @dev Should only be called in extraordinary situations by the admin of the contract
*/
function pause() external;
/**
* @notice Toggle UnPause
* @dev Should only be called in extraordinary situations by the admin of the contract
*/
function unPause() external;
/**
* @notice Deposits amount of assets in the PT vault
* @param assets The amount of assets being deposited
* @param receiver The receiver address of the shares
* @return shares The amount of shares minted (same amount for PT & yt)
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @notice Deposits amount of assets in the PT vault
* @param assets The amount of assets being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver the receiver address of the YTs
* @return shares The amount of shares minted (same amount for PT & yt)
*/
function deposit(
uint256 assets,
address ptReceiver,
address ytReceiver
) external returns (uint256 shares);
/**
* @notice Deposits amount of assets with a lower bound on shares received
* @param assets The amount of assets being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver The receiver address of the YTs
* @param minShares The minimum allowed shares from this deposit
* @return shares The amount of shares actually minted to the receiver
*/
function deposit(
uint256 assets,
address ptReceiver,
address ytReceiver,
uint256 minShares
) external returns (uint256 shares);
/**
* @notice Same as normal deposit but with IBTs
* @param ibts The amount of IBT being deposited
* @param receiver The receiver address of the shares
* @return shares The amount of shares minted to the receiver
*/
function depositIBT(uint256 ibts, address receiver) external returns (uint256 shares);
/**
* @notice Same as normal deposit but with IBTs
* @param ibts The amount of IBT being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver the receiver address of the YTs
* @return shares The amount of shares minted to the receiver
*/
function depositIBT(
uint256 ibts,
address ptReceiver,
address ytReceiver
) external returns (uint256 shares);
/**
* @notice Same as normal deposit but with IBTs
* @param ibts The amount of IBT being deposited
* @param ptReceiver The receiver address of the PTs
* @param ytReceiver The receiver address of the YTs
* @param minShares The minimum allowed shares from this deposit
* @return shares The amount of shares minted to the receiver
*/
function depositIBT(
uint256 ibts,
address ptReceiver,
address ytReceiver,
uint256 minShares
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends assets to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the assets
* @param owner The owner of the shares
* @return assets The actual amount of assets received for burning the shares
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends assets to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the assets
* @param owner The owner of the shares
* @param minAssets The minimum assets that should be returned to user
* @return assets The actual amount of assets received for burning the shares
*/
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 minAssets
) external returns (uint256 assets);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends IBTs to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares
* @return ibts The actual amount of IBT received for burning the shares
*/
function redeemForIBT(
uint256 shares,
address receiver,
address owner
) external returns (uint256 ibts);
/**
* @notice Burns owner's shares (PTs and YTs before expiry, PTs after expiry)
* and sends IBTs to receiver
* @param shares The amount of shares to burn
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares
* @param minIbts The minimum IBTs that should be returned to user
* @return ibts The actual amount of IBT received for burning the shares
*/
function redeemForIBT(
uint256 shares,
address receiver,
address owner,
uint256 minIbts
) external returns (uint256 ibts);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends assets to receiver
* @param assets The amount of assets to be received
* @param receiver The address that will receive the assets
* @param owner The owner of the shares (PTs and YTs)
* @return shares The actual amount of shares burnt for receiving the assets
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends assets to receiver
* @param assets The amount of assets to be received
* @param receiver The address that will receive the assets
* @param owner The owner of the shares (PTs and YTs)
* @param maxShares The maximum shares allowed to be burnt
* @return shares The actual amount of shares burnt for receiving the assets
*/
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxShares
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends IBTs to receiver
* @param ibts The amount of IBT to be received
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares (PTs and YTs)
* @return shares The actual amount of shares burnt for receiving the IBTs
*/
function withdrawIBT(
uint256 ibts,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @notice Burns owner's shares (before expiry : PTs and YTs) and sends IBTs to receiver
* @param ibts The amount of IBT to be received
* @param receiver The address that will receive the IBTs
* @param owner The owner of the shares (PTs and YTs)
* @param maxShares The maximum shares allowed to be burnt
* @return shares The actual amount of shares burnt for receiving the IBTs
*/
function withdrawIBT(
uint256 ibts,
address receiver,
address owner,
uint256 maxShares
) external returns (uint256 shares);
/**
* @notice Updates _user's yield since last update
* @param _user The user whose yield will be updated
* @return updatedUserYieldInIBT The unclaimed yield of the user in IBT (not just the updated yield)
*/
function updateYield(address _user) external returns (uint256 updatedUserYieldInIBT);
/**
* @notice Claims caller's unclaimed yield in asset
* @param _receiver The receiver of yield
* @param _minAssets The minimum amount of assets that should be received
* @return yieldInAsset The amount of yield claimed in asset
*/
function claimYield(
address _receiver,
uint256 _minAssets
) external returns (uint256 yieldInAsset);
/**
* @notice Claims caller's unclaimed yield in IBT
* @param _receiver The receiver of yield
* @param _minIBT The minimum amount of IBT that should be received
* @return yieldInIBT The amount of yield claimed in IBT
*/
function claimYieldInIBT(
address _receiver,
uint256 _minIBT
) external returns (uint256 yieldInIBT);
/**
* @notice Claims the collected ibt fees and redeems them to the fee collector
* @param _minAssets The minimum amount of assets that should be received
* @return assets The amount of assets sent to the fee collector
*/
function claimFees(uint256 _minAssets) external returns (uint256 assets);
/**
* @notice Updates yield of both sender and receiver of YTs
* @param _from the sender of YTs
* @param _to the receiver of YTs
*/
function beforeYtTransfer(address _from, address _to) external;
/**
* Call the claimRewards function of the rewards contract
* @param data The optional data to be passed to the rewards contract
*/
function claimRewards(bytes memory data) external;
/* SETTERS
*****************************************************************************************************************/
/**
* @notice Stores PT and IBT rates at expiry. Ideally, it should be called the day of expiry
*/
function storeRatesAtExpiry() external;
/** Set a new Rewards Proxy
* @param _rewardsProxy The address of the new reward proxy
*/
function setRewardsProxy(address _rewardsProxy) external;
/* GETTERS
*****************************************************************************************************************/
/**
* @notice Returns the amount of shares minted for the theorical deposited amount of assets
* @param assets The amount of assets deposited
* @return The amount of shares minted
*/
function previewDeposit(uint256 assets) external view returns (uint256);
/**
* @notice Returns the amount of shares minted for the theorical deposited amount of IBT
* @param ibts The amount of IBT deposited
* @return The amount of shares minted
*/
function previewDepositIBT(uint256 ibts) external view returns (uint256);
/**
* @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
* @param receiver The receiver of the shares
* @return The maximum amount of assets that can be deposited
*/
function maxDeposit(address receiver) external view returns (uint256);
/**
* @notice Returns the theorical amount of shares that need to be burnt to receive assets of underlying
* @param assets The amount of assets to receive
* @return The amount of shares burnt
*/
function previewWithdraw(uint256 assets) external view returns (uint256);
/**
* @notice Returns the theorical amount of shares that need to be burnt to receive amount of IBT
* @param ibts The amount of IBT to receive
* @return The amount of shares burnt
*/
function previewWithdrawIBT(uint256 ibts) external view returns (uint256);
/**
* @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
* @param owner The owner of the Vault shares
* @return The maximum amount of assets that can be withdrawn
*/
function maxWithdraw(address owner) external view returns (uint256);
/**
* @notice Returns the maximum amount of the IBT that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
* @param owner The owner of the Vault shares
* @return The maximum amount of IBT that can be withdrawn
*/
function maxWithdrawIBT(address owner) external view returns (uint256);
/**
* @notice Returns the amount of assets received for the theorical amount of burnt shares
* @param shares The amount of shares to burn
* @return The amount of assets received
*/
function previewRedeem(uint256 shares) external view returns (uint256);
/**
* @notice Returns the amount of IBT received for the theorical amount of burnt shares
* @param shares The amount of shares to burn
* @return The amount of IBT received
*/
function previewRedeemForIBT(uint256 shares) external view returns (uint256);
/**
* @notice Returns the maximum amount of Vault shares that can be redeemed by the owner
* @notice This function behaves differently before and after expiry. Before expiry an equal amount of PT and YT
* needs to be burnt, while after expiry only PTs are burnt.
* @param owner The owner of the shares
* @return The maximum amount of shares that can be redeemed
*/
function maxRedeem(address owner) external view returns (uint256);
/**
* Returns the total amount of the underlying asset that is owned by the Vault in the form of IBT.
*/
function totalAssets() external view returns (uint256);
/**
* @notice Converts an underlying amount in principal. Equivalent to ERC-4626's convertToShares method.
* @param underlyingAmount The amount of underlying (or assets) to convert
* @return The resulting amount of principal (or shares)
*/
function convertToPrincipal(uint256 underlyingAmount) external view returns (uint256);
/**
* @notice Converts a principal amount in underlying. Equivalent to ERC-4626's convertToAssets method.
* @param principalAmount The amount of principal (or shares) to convert
* @return The resulting amount of underlying (or assets)
*/
function convertToUnderlying(uint256 principalAmount) external view returns (uint256);
/**
* @notice Returns whether or not the contract is paused.
* @return true if the contract is paused, and false otherwise
*/
function paused() external view returns (bool);
/**
* @notice Returns the unix timestamp (uint256) at which the PT contract expires
* @return The unix timestamp (uint256) when PTs become redeemable
*/
function maturity() external view returns (uint256);
/**
* @notice Returns the duration of the PT contract
* @return The duration (in s) to expiry/maturity of the PT contract
*/
function getDuration() external view returns (uint256);
/**
* @notice Returns the address of the underlying token (or asset). Equivalent to ERC-4626's asset method.
* @return The address of the underlying token (or asset)
*/
function underlying() external view returns (address);
/**
* @notice Returns the IBT address of the PT contract
* @return ibt The address of the IBT
*/
function getIBT() external view returns (address ibt);
/**
* @notice Returns the yt address of the PT contract
* @return yt The address of the yt
*/
function getYT() external view returns (address yt);
/**
* @notice Returns the current ibtRate
* @return The current ibtRate
*/
function getIBTRate() external view returns (uint256);
/**
* @notice Returns the current ptRate
* @return The current ptRate
*/
function getPTRate() external view returns (uint256);
/**
* @notice Returns 1 unit of IBT
* @return The IBT unit
*/
function getIBTUnit() external view returns (uint256);
/**
* @notice Get the unclaimed fees in IBT
* @return The unclaimed fees in IBT
*/
function getUnclaimedFeesInIBT() external view returns (uint256);
/**
* @notice Get the total collected fees in IBT (claimed and unclaimed)
* @return The total fees in IBT
*/
function getTotalFeesInIBT() external view returns (uint256);
/**
* @notice Get the tokenization fee of the PT
* @return The tokenization fee
*/
function getTokenizationFee() external view returns (uint256);
/**
* @notice Get the current IBT yield of the user
* @param _user The address of the user to get the current yield from
* @return The yield of the user in IBT
*/
function getCurrentYieldOfUserInIBT(address _user) external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.4;
interface IStableSwapNG {
function A() external view returns (uint256);
function A_precise() external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function D_ma_time() external view returns (uint256);
function D_oracle() external view returns (uint256);
function N_COINS() external view returns (uint256);
function add_liquidity(
uint256[] memory _amounts,
uint256 _min_mint_amount,
address _receiver
) external returns (uint256);
function admin_balances(uint256 arg0) external view returns (uint256);
function admin_fee() external view returns (uint256);
function allowance(address arg0, address arg1) external view returns (uint256);
function approve(address _spender, uint256 _value) external returns (bool);
function balanceOf(address arg0) external view returns (uint256);
function balances(uint256 i) external view returns (uint256);
function calc_token_amount(
uint256[] memory _amounts,
bool _is_deposit
) external view returns (uint256);
function calc_withdraw_one_coin(uint256 _burn_amount, int128 i) external view returns (uint256);
function coins(uint256 arg0) external view returns (address);
function decimals() external view returns (uint8);
function dynamic_fee(int128 i, int128 j) external view returns (uint256);
function ema_price(uint256 i) external view returns (uint256);
function exchange(int128 i, int128 j, uint256 _dx, uint256 _min_dy) external returns (uint256);
function exchange(
int128 i,
int128 j,
uint256 _dx,
uint256 _min_dy,
address _receiver
) external returns (uint256);
function exchange_received(
int128 i,
int128 j,
uint256 _dx,
uint256 _min_dy
) external returns (uint256);
function exchange_received(
int128 i,
int128 j,
uint256 _dx,
uint256 _min_dy,
address _receiver
) external returns (uint256);
function fee() external view returns (uint256);
function future_A() external view returns (uint256);
function future_A_time() external view returns (uint256);
function get_balances() external view returns (uint256[] memory);
function get_dx(int128 i, int128 j, uint256 dy) external view returns (uint256);
function get_dy(int128 i, int128 j, uint256 dx) external view returns (uint256);
function get_p(uint256 i) external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function initial_A() external view returns (uint256);
function initial_A_time() external view returns (uint256);
function last_price(uint256 i) external view returns (uint256);
function ma_exp_time() external view returns (uint256);
function ma_last_time() external view returns (uint256);
function name() external view returns (string memory);
function nonces(address arg0) external view returns (uint256);
function offpeg_fee_multiplier() external view returns (uint256);
function permit(
address _owner,
address _spender,
uint256 _value,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external returns (bool);
function price_oracle(uint256 i) external view returns (uint256);
function ramp_A(uint256 _future_A, uint256 _future_time) external;
function remove_liquidity(
uint256 _burn_amount,
uint256[] memory _min_amounts
) external returns (uint256[] memory);
function remove_liquidity(
uint256 _burn_amount,
uint256[] memory _min_amounts,
address _receiver
) external returns (uint256[] memory);
function remove_liquidity(
uint256 _burn_amount,
uint256[] memory _min_amounts,
address _receiver,
bool _claim_admin_fees
) external returns (uint256[] memory);
function remove_liquidity_imbalance(
uint256[] memory _amounts,
uint256 _max_burn_amount
) external returns (uint256);
function remove_liquidity_imbalance(
uint256[] memory _amounts,
uint256 _max_burn_amount,
address _receiver
) external returns (uint256);
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received
) external returns (uint256);
function remove_liquidity_one_coin(
uint256 _burn_amount,
int128 i,
uint256 _min_received,
address _receiver
) external returns (uint256);
function salt() external view returns (bytes32);
function set_ma_exp_time(uint256 _ma_exp_time, uint256 _D_ma_time) external;
function set_new_fee(uint256 _new_fee, uint256 _new_offpeg_fee_multiplier) external;
function stop_ramp_A() external;
function stored_rates() external view returns (uint256[] memory);
function symbol() external view returns (string memory);
function totalSupply() external view returns (uint256);
function transfer(address _to, uint256 _value) external returns (bool);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function version() external view returns (string memory);
function withdraw_admin_fees() external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
import "../interfaces/ICurvePool.sol";
import "../interfaces/ICurveNGPool.sol";
import "../interfaces/IStableSwapNG.sol";
import "../interfaces/IPrincipalToken.sol";
import "./RayMath.sol";
import "openzeppelin-math/Math.sol";
/**
* @title CurvePoolUtil library
* @author Spectra Finance
* @notice Provides miscellaneous utils for computations related to Curve CryptoSwap pools.
*/
library CurvePoolUtil {
using Math for uint256;
using RayMath for uint256;
error SolutionNotFound();
error FailedToFetchExpectedLPTokenAmount();
error FailedToFetchExpectedCoinAmount();
/// @notice Decimal precision used internally in the Curve AMM
uint256 public constant CURVE_DECIMALS = 18;
/// @notice Base unit for Curve AMM calculations
uint256 public constant CURVE_UNIT = 1e18;
/// @notice Make rounding errors favoring other LPs a tiny bit
uint256 private constant APPROXIMATION_DECREMENT = 1;
/// @notice Maximal number of iterations in the binary search algorithm
uint256 private constant MAX_ITERATIONS_BINSEARCH = 255;
/**
* @notice Returns the expected LP token amount received for depositing given amounts of IBT and PT
* @notice Method to be used with legacy Curve Cryptoswap pools
* @param _curvePool The address of the Curve Pool in which liquidity will be deposited
* @param _amounts Array containing the amounts of IBT and PT to deposit in the Curve Pool
* @return minMintAmount The amount of expected LP tokens received for depositing the liquidity in the pool
*/
function previewAddLiquidity(
address _curvePool,
uint256[2] memory _amounts
) external view returns (uint256 minMintAmount) {
(bool success, bytes memory responseData) = _curvePool.staticcall(
abi.encodeCall(ICurvePool(address(0)).calc_token_amount, (_amounts))
);
if (!success) {
revert FailedToFetchExpectedLPTokenAmount();
}
minMintAmount = abi.decode(responseData, (uint256));
}
/**
* @notice Returns the expected LP token amount received for depositing given amounts of IBT and PT
* @notice Method to be used with legacy Curve Cryptoswap NG pools
* @param _curvePool The address of the Curve Pool in which liquidity will be deposited
* @param _amounts Array containing the amounts of IBT and PT to deposit in the Curve Pool
* @return minMintAmount The amount of expected LP tokens received for depositing the liquidity in the pool
*/
function previewAddLiquidityNG(
address _curvePool,
uint256[2] memory _amounts
) external view returns (uint256 minMintAmount) {
(bool success, bytes memory responseData) = _curvePool.staticcall(
abi.encodeCall(ICurveNGPool(address(0)).calc_token_amount, (_amounts, true))
);
if (!success) {
revert FailedToFetchExpectedLPTokenAmount();
}
minMintAmount = abi.decode(responseData, (uint256));
}
/**
* @notice Returns the expected LP token amount received for depositing given amounts of IBT and PT
* @notice Method to be used with StableSwap NG pools
* @param _curvePool The address of the Curve Pool in which liquidity will be deposited
* @param _amounts Array containing the amounts of IBT and PT to deposit in the Curve Pool
* @return minMintAmount The amount of expected LP tokens received for depositing the liquidity in the pool
*/
function previewAddLiquiditySNG(
address _curvePool,
uint256[] memory _amounts
) external view returns (uint256 minMintAmount) {
// @dev set the is_deposit to true
(bool success, bytes memory responseData) = _curvePool.staticcall(
abi.encodeCall(IStableSwapNG(address(0)).calc_token_amount, (_amounts, true))
);
if (!success) {
revert FailedToFetchExpectedLPTokenAmount();
}
minMintAmount = abi.decode(responseData, (uint256));
}
/**
* @notice Returns the IBT and PT amounts received for burning a given amount of LP tokens
* @notice Method to be used with legacy Curve Cryptoswap pools
* @param _curvePool The address of the curve pool
* @param _lpTokenAmount The amount of the lp token to burn
* @return minAmounts The expected respective amounts of IBT and PT withdrawn from the curve pool
*/
function previewRemoveLiquidity(
address _curvePool,
uint256 _lpTokenAmount
) external view returns (uint256[2] memory minAmounts) {
address lpToken = ICurvePool(_curvePool).token();
uint256 totalSupply = IERC20(lpToken).totalSupply();
(uint256 ibtBalance, uint256 ptBalance) = _getCurvePoolBalances(_curvePool);
// decrement following what Curve is doing
if (_lpTokenAmount > APPROXIMATION_DECREMENT && totalSupply != 0) {
_lpTokenAmount -= APPROXIMATION_DECREMENT;
minAmounts = [
(ibtBalance * _lpTokenAmount) / totalSupply,
(ptBalance * _lpTokenAmount) / totalSupply
];
} else {
minAmounts = [uint256(0), uint256(0)];
}
}
/**
* @notice Returns the IBT and PT amounts received for burning a given amount of LP tokens
* @notice Method to be used with Curve Cryptoswap NG pools
* @param _curvePool The address of the curve pool
* @param _lpTokenAmount The amount of the lp token to burn
* @return minAmounts The expected respective amounts of IBT and PT withdrawn from the curve pool
*/
function previewRemoveLiquidityNG(
address _curvePool,
uint256 _lpTokenAmount
) external view returns (uint256[2] memory minAmounts) {
uint256 totalSupply = ICurveNGPool(_curvePool).totalSupply();
(uint256 ibtBalance, uint256 ptBalance) = _getCurvePoolBalances(_curvePool);
// reproduces Curve implementation
if (_lpTokenAmount == totalSupply) {
minAmounts = [ibtBalance, ptBalance];
} else if (_lpTokenAmount > APPROXIMATION_DECREMENT && totalSupply != 0) {
_lpTokenAmount -= APPROXIMATION_DECREMENT;
minAmounts = [
ibtBalance.mulDiv(_lpTokenAmount, totalSupply),
ptBalance.mulDiv(_lpTokenAmount, totalSupply)
];
} else {
minAmounts = [uint256(0), uint256(0)];
}
}
/**
* @notice Returns the IBT and PT amounts received for burning a given amount of LP tokens
* @notice Method to be used with StableSwap NG pools
* @param _curvePool The address of the curve pool
* @param _lpTokenAmount The amount of the lp token to burn
* @return minAmounts The expected respective amounts of IBT and PT withdrawn from the curve pool
*/
function previewRemoveLiquiditySNG(
address _curvePool,
uint256 _lpTokenAmount
) external view returns (uint256[] memory) {
uint256 totalSupply = IERC20(_curvePool).totalSupply();
(uint256 ibtBalance, uint256 ptBalance) = _getCurvePoolBalances(_curvePool);
// decrement following what Curve is doing
uint256[] memory minAmounts = new uint256[](2);
if (_lpTokenAmount > APPROXIMATION_DECREMENT && totalSupply != 0) {
_lpTokenAmount -= APPROXIMATION_DECREMENT;
minAmounts[0] = (ibtBalance * _lpTokenAmount) / totalSupply;
minAmounts[1] = (ptBalance * _lpTokenAmount) / totalSupply;
} else {
minAmounts[0] = 0;
minAmounts[1] = 0;
}
return minAmounts;
}
/**
* @notice Returns the amount of coin i received for burning a given amount of LP tokens
* @notice Method to be used with legacy Curve CryptoSwap pools
* @param _curvePool The address of the curve pool
* @param _lpTokenAmount The amount of the LP tokens to burn
* @param _i The index of the unique coin to withdraw
* @return minAmount The expected amount of coin i withdrawn from the curve pool
*/
function previewRemoveLiquidityOneCoin(
address _curvePool,
uint256 _lpTokenAmount,
uint256 _i
) external view returns (uint256 minAmount) {
(bool success, bytes memory responseData) = _curvePool.staticcall(
abi.encodeCall(ICurvePool(address(0)).calc_withdraw_one_coin, (_lpTokenAmount, _i))
);
if (!success) {
revert FailedToFetchExpectedCoinAmount();
}
minAmount = abi.decode(responseData, (uint256));
}
/**
* @notice Returns the amount of coin i received for burning a given amount of LP tokens
* @notice Method to be used with Curve NG pools
* @param _curvePool The address of the curve pool
* @param _lpTokenAmount The amount of the LP tokens to burn
* @param _i The index of the unique coin to withdraw
* @return minAmount The expected amount of coin i withdrawn from the curve pool
*/
function previewRemoveLiquidityOneCoinNG(
address _curvePool,
uint256 _lpTokenAmount,
uint256 _i
) external view returns (uint256 minAmount) {
(bool success, bytes memory responseData) = _curvePool.staticcall(
abi.encodeCall(ICurveNGPool(address(0)).calc_withdraw_one_coin, (_lpTokenAmount, _i))
);
if (!success) {
revert FailedToFetchExpectedCoinAmount();
}
minAmount = abi.decode(responseData, (uint256));
}
/**
* @notice Returns the amount of coin i received for burning a given amount of LP tokens
* @notice Method to be used with StableSwap NG pools
* @param _curvePool The address of the curve pool
* @param _lpTokenAmount The amount of the LP tokens to burn
* @param _i The index of the unique coin to withdraw
* @return minAmount The expected amount of coin i withdrawn from the curve pool
*/
function previewRemoveLiquidityOneCoinSNG(
address _curvePool,
uint256 _lpTokenAmount,
int128 _i
) external view returns (uint256 minAmount) {
(bool success, bytes memory responseData) = _curvePool.staticcall(
abi.encodeCall(IStableSwapNG(address(0)).calc_withdraw_one_coin, (_lpTokenAmount, _i))
);
if (!success) {
revert FailedToFetchExpectedCoinAmount();
}
minAmount = abi.decode(responseData, (uint256));
}
/**
* @notice Return the amount of IBT to deposit in the curve pool, given the total amount of IBT available for deposit
* @param _amount The total amount of IBT available for deposit
* @param _curvePool The address of the pool to deposit the amounts
* @param _pt The address of the PT
* @return ibts The amount of IBT which will be deposited in the curve pool
*/
function calcIBTsToTokenizeForCurvePool(
uint256 _amount,
address _curvePool,
address _pt
) external view returns (uint256 ibts) {
(uint256 ibtBalance, uint256 ptBalance) = _getCurvePoolBalances(_curvePool);
uint256 ibtBalanceInPT = IPrincipalToken(_pt).previewDepositIBT(ibtBalance);
// Liquidity added in a ratio that (closely) matches the existing pool's ratio
ibts = _amount.mulDiv(ptBalance, ibtBalanceInPT + ptBalance);
}
/**
* @notice Return the amount of IBT to deposit in the curve pool given the proportion in which we want to deposit, given the total amount of IBT available for deposit
* @param _amount The total amount of IBT available for deposit
* @param _prop The proportion in which we want to make the deposit: _prop = nIBT / (nIBT + nPT)
* @param _pt The address of the PT
* @return ibts The amount of IBT which will be deposited in the curve pool
*/
function calcIBTsToTokenizeForCurvePoolCustomProp(
uint256 _amount,
uint256 _prop,
address _pt
) external view returns (uint256 ibts) {
uint256 rate = IPrincipalToken(_pt).previewDepositIBT(_amount).mulDiv(CURVE_UNIT, _amount);
ibts = _amount.mulDiv(CURVE_UNIT, CURVE_UNIT + _prop.mulDiv(rate, CURVE_UNIT));
}
/**
* @param _curvePool : PT/IBT curve pool
* @param _i token index
* @param _j token index
* @param _targetDy amount out desired
* @return dx The amount of token to provide in order to obtain _targetDy after swap
*/
function getDx(
address _curvePool,
uint256 _i,
uint256 _j,
uint256 _targetDy
) external view returns (uint256 dx) {
// Initial guesses
uint256 _minGuess = type(uint256).max;
uint256 _maxGuess = type(uint256).max;
uint256 _factor100;
uint256 _guess = ICurvePool(_curvePool).get_dy(_i, _j, _targetDy);
if (_guess > _targetDy) {
_maxGuess = _targetDy;
_factor100 = 10;
} else {
_minGuess = _targetDy;
_factor100 = 1000;
}
uint256 loops;
_guess = _targetDy;
while (!_dxSolved(_curvePool, _i, _j, _guess, _targetDy, _minGuess, _maxGuess)) {
loops++;
(_minGuess, _maxGuess, _guess) = _runLoop(
_minGuess,
_maxGuess,
_factor100,
_guess,
_targetDy,
_curvePool,
_i,
_j
);
if (loops >= MAX_ITERATIONS_BINSEARCH) {
revert SolutionNotFound();
}
}
dx = _guess;
}
/**
* @dev Runs bisection search
* @param _minGuess lower bound on searched value
* @param _maxGuess upper bound on searched value
* @param _factor100 search interval scaling factor
* @param _guess The previous guess for the `dx` value that is being refined through the search process
* @param _targetDy The target output of the `get_dy` function, which the search aims to achieve by adjusting `dx`.
* @param _curvePool PT/IBT curve pool
* @param _i token index, either 0 or 1
* @param _j token index, either 0 or 1, must be different than _i
* @return The lower bound on _guess, upper bound on _guess and next _guess
*/
function _runLoop(
uint256 _minGuess,
uint256 _maxGuess,
uint256 _factor100,
uint256 _guess,
uint256 _targetDy,
address _curvePool,
uint256 _i,
uint256 _j
) internal view returns (uint256, uint256, uint256) {
if (_minGuess == type(uint256).max || _maxGuess == type(uint256).max) {
_guess = (_guess * _factor100) / 100;
} else {
_guess = (_maxGuess + _minGuess) >> 1;
}
uint256 dy = ICurvePool(_curvePool).get_dy(_i, _j, _guess);
if (dy < _targetDy) {
_minGuess = _guess;
} else if (dy > _targetDy) {
_maxGuess = _guess;
}
return (_minGuess, _maxGuess, _guess);
}
/**
* @dev Returns true if algorithm converged
* @param _curvePool PT/IBT curve pool
* @param _i token index, either 0 or 1
* @param _j token index, either 0 or 1, must be different than _i
* @param _dx The current guess for the `dx` value that is being refined through the search process.
* @param _targetDy The target output of the `get_dy` function, which the search aims to achieve by adjusting `dx`.
* @param _minGuess lower bound on searched value
* @param _maxGuess upper bound on searched value
* @return true if the solution to the search problem was found, false otherwise
*/
function _dxSolved(
address _curvePool,
uint256 _i,
uint256 _j,
uint256 _dx,
uint256 _targetDy,
uint256 _minGuess,
uint256 _maxGuess
) internal view returns (bool) {
if (_minGuess == type(uint256).max || _maxGuess == type(uint256).max) {
return false;
}
uint256 dy = ICurvePool(_curvePool).get_dy(_i, _j, _dx);
if (dy == _targetDy) {
return true;
}
uint256 dy1 = ICurvePool(_curvePool).get_dy(_i, _j, _dx + 1);
if (dy < _targetDy && _targetDy < dy1) {
return true;
}
return false;
}
/**
* @notice Returns the balances of the two tokens in provided curve pool
* @param _curvePool address of the curve pool
* @return The IBT and PT balances of the curve pool
*/
function _getCurvePoolBalances(address _curvePool) internal view returns (uint256, uint256) {
return (ICurvePool(_curvePool).balances(0), ICurvePool(_curvePool).balances(1));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
/**
* @title RayMath library
* @author Spectra Finance
* @notice Provides conversions for/to any decimal tokens to/from ray.
* @dev Conversions from Ray are rounded down.
*/
library RayMath {
/// @dev 27 decimal unit
uint256 public constant RAY_UNIT = 1e27;
uint256 public constant RAY_DECIMALS = 27;
/**
* @dev Converts a value from Ray (27-decimal precision) to a representation with a specified number of decimals.
* @param _a The amount in Ray to be converted. Ray is a fixed-point representation with 27 decimals.
* @param _decimals The target decimal precision for the converted amount.
* @return b The amount converted from Ray to the specified decimal precision.
*/
function fromRay(uint256 _a, uint256 _decimals) internal pure returns (uint256 b) {
uint256 decimals_ratio = 10 ** (RAY_DECIMALS - _decimals);
assembly {
b := div(_a, decimals_ratio)
}
}
/**
* @dev Converts a value from Ray (27-decimal precision) to a representation with a specified number of decimals.
* @param _a The amount in Ray to be converted. Ray is a fixed-point representation with 27 decimals.
* @param _decimals The target decimal precision for the converted amount.
* @param _roundUp If true, the function rounds up the result to the nearest integer value.
* If false, it truncates (rounds down) to the nearest integer.
* @return b The amount converted from Ray to the specified decimal precision, rounded as specified.
*/
function fromRay(
uint256 _a,
uint256 _decimals,
bool _roundUp
) internal pure returns (uint256 b) {
uint256 decimals_ratio = 10 ** (RAY_DECIMALS - _decimals);
assembly {
b := div(_a, decimals_ratio)
if and(eq(_roundUp, 1), gt(mod(_a, decimals_ratio), 0)) {
b := add(b, 1)
}
}
}
/**
* @dev Converts a value with a specified number of decimals to Ray (27-decimal precision).
* @param _a The amount to be converted, specified in a decimal format.
* @param _decimals The number of decimals in the representation of 'a'.
* @return b The amount in Ray, converted from the specified decimal precision.
* Ensures that the conversion maintains the value's integrity (no overflow).
*/
function toRay(uint256 _a, uint256 _decimals) internal pure returns (uint256 b) {
uint256 decimals_ratio = 10 ** (RAY_DECIMALS - _decimals);
// to avoid overflow, b/decimals_ratio == _a
assembly {
b := mul(_a, decimals_ratio)
if iszero(eq(div(b, decimals_ratio), _a)) {
revert(0, 0)
}
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.20;
library Constants {
/// @dev 18 decimal unit
uint256 internal constant UNIT = 1e18;
/// @dev identifier for native ETH
address public constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @dev maximal number of iterations in the secant method algorithm
uint256 internal constant MAX_ITERATIONS_SECANT = 255;
/// @dev maximal number of iterations in the linear search following secant method algorithm
uint256 internal constant MAX_ITERATIONS_LINEAR_SEARCH = 255;
/// @dev determines the rate at which an input value is scaled in each iteration of linear search
uint256 internal constant SCALING_FACTOR_LINEAR_SEARCH = 1e6;
/// @dev precision divisor for the secant method
uint256 internal constant PRECISION_DIVISOR = 1000;
/// @dev Used for identifying cases when this contract's balance of a token is to be used as an input
/// This value is equivalent to 1<<255, i.e. a singular 1 in the most significant bit.
uint256 internal constant CONTRACT_BALANCE =
0x8000000000000000000000000000000000000000000000000000000000000000;
/// @dev Used as a flag for identifying that msg.sender should be used, saves gas by sending more 0 bytes
address internal constant MSG_SENDER = address(0xc0);
/// @dev Used as a flag for identifying address(this) should be used, saves gas by sending more 0 bytes
address internal constant ADDRESS_THIS = address(0xe0);
}{
"evmVersion": "shanghai",
"libraries": {
"src/libraries/CurvePoolUtil.sol": {
"CurvePoolUtil": "0x27857F8E0EEE20596e7cE5be3901efd663E91e10"
},
"src/libraries/NamingUtil.sol": {
"NamingUtil": "0x0347772f901f6324095aB8547FE5158B2eb93549"
},
"src/libraries/PrincipalTokenUtil.sol": {
"PrincipalTokenUtil": "0x622BCCf6B8A472a89be0ED4dBEe6C02600cE37f3"
}
},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
"openzeppelin-erc20-basic/=lib/openzeppelin-contracts/contracts/token/ERC20/",
"openzeppelin-erc20-extensions/=lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/",
"openzeppelin-erc20/=lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/",
"openzeppelin-math/=lib/openzeppelin-contracts/contracts/utils/math/",
"openzeppelin-proxy/=lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/",
"openzeppelin-utils/=lib/openzeppelin-contracts/contracts/utils/",
"config/=lib/spectra-contracts-configs/script/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"DiamondRouter/=lib/DiamondRouter/",
"halmos-cheatcodes/=lib/DiamondRouter/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"solidity-stringutils/=lib/DiamondRouter/lib/solidity-stringutils/",
"spectra-contracts-configs/=lib/spectra-contracts-configs/"
],
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"i","type":"uint256"},{"internalType":"uint256","name":"j","type":"uint256"}],"name":"InvalidTokenIndex","type":"error"},{"inputs":[],"name":"MathOverflowedMulDiv","type":"error"},{"inputs":[],"name":"PoolLiquidityError","type":"error"},{"inputs":[],"name":"ResultNotFound","type":"error"},{"inputs":[{"internalType":"int256","name":"value","type":"int256"}],"name":"SafeCastOverflowedIntToUint","type":"error"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintToInt","type":"error"},{"inputs":[],"name":"UnsufficientAmountForFlashFee","type":"error"},{"inputs":[{"internalType":"uint256","name":"_inputIBTAmount","type":"uint256"},{"internalType":"address","name":"_curvePool","type":"address"}],"name":"convertIBTToYTSpot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_inputIBTAmount","type":"uint256"},{"internalType":"address","name":"_curvePool","type":"address"}],"name":"convertIBTToYTSpotSNG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_pt","type":"address"}],"name":"getPTUnderlyingUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256[2]","name":"_amounts","type":"uint256[2]"}],"name":"previewAddLiquidity","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"previewAddLiquiditySNG","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"previewAddLiquidityWithAsset","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"previewAddLiquidityWithAssetSNG","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_ibts","type":"uint256"}],"name":"previewAddLiquidityWithIBT","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_ibts","type":"uint256"}],"name":"previewAddLiquidityWithIBTSNG","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_inputIBTAmount","type":"uint256"}],"name":"previewFlashSwapExactIBTToYT","outputs":[{"internalType":"uint256","name":"ytAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedIBTAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_inputIBTAmount","type":"uint256"}],"name":"previewFlashSwapExactIBTToYTSNG","outputs":[{"internalType":"uint256","name":"ytAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedIBTAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"inputYTAmount","type":"uint256"}],"name":"previewFlashSwapExactYTToIBT","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"inputYTAmount","type":"uint256"}],"name":"previewFlashSwapExactYTToIBTSNG","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_outputYTAmount","type":"uint256"}],"name":"previewFlashSwapIBTToExactYT","outputs":[{"internalType":"uint256","name":"inputIBTAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedIBTAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_outputYTAmount","type":"uint256"}],"name":"previewFlashSwapIBTToExactYTSNG","outputs":[{"internalType":"uint256","name":"inputIBTAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedIBTAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256[2]","name":"_amounts","type":"uint256[2]"}],"name":"previewNGAddLiquidity","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_assets","type":"uint256"}],"name":"previewNGAddLiquidityWithAsset","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_ibts","type":"uint256"}],"name":"previewNGAddLiquidityWithIBT","outputs":[{"internalType":"uint256","name":"minMintAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_inputIBTAmount","type":"uint256"}],"name":"previewNGFlashSwapExactIBTToYT","outputs":[{"internalType":"uint256","name":"ytAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedIBTAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"inputYTAmount","type":"uint256"}],"name":"previewNGFlashSwapExactYTToIBT","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_outputYTAmount","type":"uint256"}],"name":"previewNGFlashSwapIBTToExactYT","outputs":[{"internalType":"uint256","name":"inputIBTAmount","type":"uint256"},{"internalType":"uint256","name":"borrowedIBTAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewNGRemoveLiquidity","outputs":[{"internalType":"uint256[2]","name":"minAmounts","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewNGRemoveLiquidityForAsset","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewNGRemoveLiquidityForIBT","outputs":[{"internalType":"uint256","name":"ibts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"},{"internalType":"uint256","name":"_i","type":"uint256"}],"name":"previewNGRemoveLiquidityOneCoin","outputs":[{"internalType":"uint256","name":"minAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewRemoveLiquidity","outputs":[{"internalType":"uint256[2]","name":"minAmounts","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewRemoveLiquidityForAsset","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewRemoveLiquidityForAssetSNG","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewRemoveLiquidityForIBT","outputs":[{"internalType":"uint256","name":"ibts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewRemoveLiquidityForIBTSNG","outputs":[{"internalType":"uint256","name":"ibts","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"},{"internalType":"uint256","name":"_i","type":"uint256"}],"name":"previewRemoveLiquidityOneCoin","outputs":[{"internalType":"uint256","name":"minAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"},{"internalType":"int128","name":"_i","type":"int128"}],"name":"previewRemoveLiquidityOneCoinSNG","outputs":[{"internalType":"uint256","name":"minAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_lpAmount","type":"uint256"}],"name":"previewRemoveLiquiditySNG","outputs":[{"internalType":"uint256[]","name":"minAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"uint256","name":"_i","type":"uint256"},{"internalType":"uint256","name":"_j","type":"uint256"}],"name":"spotExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_curvePool","type":"address"},{"internalType":"int128","name":"_i","type":"int128"},{"internalType":"int128","name":"_j","type":"int128"}],"name":"spotExchangeRateSNG","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561000f575f80fd5b506139768061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610213575f3560e01c8063794b40441161011f578063a0f3b821116100a9578063b688026d11610079578063b688026d146104a6578063b775c261146104b9578063d0a3fcb4146104cc578063f829c8f7146104df578063f8fc815c146104f2575f80fd5b8063a0f3b8211461045a578063a3284ec81461046d578063a9982ee814610480578063b03ae38114610493575f80fd5b806386b3b868116100ef57806386b3b868146103fb57806388a312e21461040e57806394e5ef67146104215780639b88c6db146104345780639c8d5a5b14610447575f80fd5b8063794b4044146103af5780637c3bdb28146103c2578063800738e9146103d557806384943214146103e8575f80fd5b80635e16f1e9116101a05780636b0426cb116101705780636b0426cb146103435780636c5b196a14610356578063719fbb27146103765780637441de6a1461038957806378c090931461039c575f80fd5b80635e16f1e9146102ea5780635fa5a497146102fd578063625aefd2146103105780636525e5f114610323575f80fd5b80632271e1f8116101e65780632271e1f8146102765780632fee2f091461028957806331922b4b1461029c5780634346b24f146102c457806344cee8f7146102d7575f80fd5b80630d029aa5146102175780630f9c83281461023d578063102c05e51461025057806314633b6814610263575b5f80fd5b61022a610225366004613207565b610505565b6040519081526020015b60405180910390f35b61022a61024b36600461329f565b610740565b61022a61025e36600461329f565b6107c1565b61022a610271366004613325565b6107fc565b61022a610284366004613367565b6109f2565b61022a610297366004613399565b610b1f565b6102af6102aa366004613207565b610cb5565b60408051928352602083019190915201610234565b61022a6102d23660046133ea565b610fe0565b61022a6102e5366004613207565b61101b565b6102af6102f8366004613207565b611224565b61022a61030b366004613490565b6114c5565b6102af61031e366004613207565b611531565b610336610331366004613207565b611836565b60405161023491906134ab565b61022a610351366004613207565b6118b5565b610369610364366004613207565b6119a1565b60405161023491906134db565b6102af610384366004613207565b611a1e565b6102af610397366004613207565b611a35565b61022a6103aa366004613399565b611c3a565b61022a6103bd366004613367565b611d87565b6102af6103d0366004613207565b611e12565b61022a6103e3366004613367565b611e1e565b61022a6103f6366004613207565b611e6e565b61022a610409366004613207565b61204e565b61022a61041c366004613207565b6121de565b61033661042f366004613207565b6122c1565b61022a610442366004613207565b612302565b61022a61045536600461351e565b61233d565b61022a610468366004613207565b612390565b61022a61047b366004613207565b612473565b6102af61048e366004613207565b6125d5565b6102af6104a1366004613207565b6127aa565b61022a6104b4366004613207565b6129ed565b6102af6104c7366004613207565b612c05565b61022a6104da366004613207565b612dda565b61022a6104ed366004613207565b612f6c565b61022a610500366004613490565b612fa7565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636525e5f185856040518363ffffffff1660e01b8152600401610540929190613550565b6040805180830381865af415801561055a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061057e9190613569565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa1580156105c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e891906135c5565b6001600160a01b0316634cdad50682600160200201516040518263ffffffff1660e01b815260040161061c91815260200190565b602060405180830381865afa158015610637573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061065b91906135f4565b60405163c661065760e01b81525f60048201526001600160a01b0386169063c661065790602401602060405180830381865afa15801561069d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c191906135c5565b825160405163266d6a8360e11b815260048101919091526001600160a01b039190911690634cdad506906024015b602060405180830381865afa15801561070a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061072e91906135f4565b610738919061361f565b949350505050565b6040516301f3906560e31b81525f907327857f8e0eee20596e7ce5be3901efd663e91e1090630f9c83289061077b9086908690600401613632565b602060405180830381865af4158015610796573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ba91906135f4565b9392505050565b6040516370b3fe7560e01b81525f907327857f8e0eee20596e7ce5be3901efd663e91e10906370b3fe759061077b9086908690600401613632565b604051631c98d5a960e11b81525f600482018190529081906001600160a01b03861690633931ab5290602401602060405180830381865afa158015610843573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086791906135f4565b90505f856001600160a01b031663fd0684b16040518163ffffffff1660e01b81526004015f60405180830381865afa1580156108a5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526108cc9190810190613672565b905084600f0b5f1480156108e3575083600f0b6001145b156109565761094c670de0b6b3a764000083610945670de0b6b3a764000085600181518110610914576109146135e0565b6020026020010151865f8151811061092e5761092e6135e0565b6020026020010151612fe79092919063ffffffff16565b9190612fe7565b92506107ba915050565b84600f0b600114801561096b575083600f0b5f145b156109b85761094c81600181518110610986576109866135e0565b6020026020010151825f815181106109a0576109a06135e0565b602002602001015184612fe79092919063ffffffff16565b60405163175ebd2b60e11b81526fffffffffffffffffffffffffffffffff8087166004830152851660248201526044015b60405180910390fd5b5f82158015610a015750816001145b15610a8957610a82670de0b6b3a7640000856001600160a01b031663c146bf946040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a4e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7291906135f4565b670de0b6b3a76400009190612fe7565b90506107ba565b826001148015610a97575081155b15610afc57836001600160a01b031663c146bf946040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ad8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8291906135f4565b60405163175ebd2b60e11b815260048101849052602481018390526044016109e9565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0384169063c661065790602401602060405180830381865afa158015610b66573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a91906135c5565b90505f816001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bed91906135f4565b90505f826001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5091906135f4565b90505f610c6c83670de0b6b3a76400006109458960015f6109f2565b905081811115610c8f5760405163202f312b60e21b815260040160405180910390fd5b5f610c9a82846136f3565b9050610ca7888583612fe7565b955050505050505b92915050565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa158015610cfe573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d2291906135c5565b6040516302f6fa9560e11b8152600481018690529091505f906001600160a01b038316906305edf52a90602401602060405180830381865afa158015610d6a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d8e91906135f4565b90505f610d9b8688611c3a565b60405163c661065760e01b81525f60048201819052919250610e0b906001600160a01b038a169063c6610657906024015b602060405180830381865afa158015610de7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061030b91906135c5565b90505f5b60ff811015610f1c57610e246103e88361371a565b610e3c83610e3287876130a6565b61094588886130bb565b10610f1c575f610e4c8a866125d5565b5090505f610e5a8b866125d5565b5090505f610e678b6130dc565b610e70846130dc565b610e7a919061372d565b90505f610e868c6130dc565b610e8f846130dc565b610e99919061372d565b9050808203610eab5750505050610f1c565b5f610f01610eb9848461372d565b610ec28b6130dc565b610ecb8b6130dc565b610ed5919061372d565b610edf9085613753565b610ee99190613782565b610ef28a6130dc565b610efc919061372d565b61310c565b979850610f1594508593506137ae92505050565b9050610e0f565b50610f278383613131565b95505f610f3489886125d5565b9650905087811115610f9057620f42405f5b60ff811015610f8d57610f65610f5d6001846136f3565b8a9084612fe7565b9850610f718b8a6125d5565b9850925089831115610f8d57610f86816137ae565b9050610f46565b50505b87811180610fb65750610fa56103e88361371a565b610fb4838a6109458c866130bb565b115b15610fd457604051635aae0c9960e11b815260040160405180910390fd5b50505050509250929050565b604051634346b24f60e01b81525f907327857f8e0eee20596e7ce5be3901efd663e91e1090634346b24f9061077b90869086906004016137c6565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa158015611062573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108691906135c5565b60405163fbfc779760e01b8152600481018590526001600160a01b038087166024830152821660448201529091505f907327857f8e0eee20596e7ce5be3901efd663e91e109063fbfc779790606401602060405180830381865af41580156110f0573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061111491906135f4565b90505f61112182866136f3565b6040516302f6fa9560e11b8152600481018490529091505f906001600160a01b038516906305edf52a90602401602060405180830381865afa158015611169573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061118d91906135f4565b6040805180820182528481526020810183905290516370b3fe7560e01b81529192507327857f8e0eee20596e7ce5be3901efd663e91e10916370b3fe75916111da918b9190600401613632565b602060405180830381865af41580156111f5573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061121991906135f4565b979650505050505050565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa15801561126d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061129191906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112f491906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611333573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135791906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611396573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ba91906135f4565b604051631bf69d3d60e11b81525f6004820181905260016024830152604482018a90529192506001600160a01b038a16906337ed3a7a906064015b602060405180830381865afa158015611410573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061143491906135f4565b90505f611442898486612fe7565b90505f61145087878561313f565b9050818311156114735760405163202f312b60e21b815260040160405180910390fd5b8161147e828561361f565b111561149d57604051638a7ceb6f60e01b815260040160405180910390fd5b5f816114a985856136f3565b6114b391906136f3565b9c939b50929950505050505050505050565b5f816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611502573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611526919061381b565b610caf90600a61391b565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa15801561157a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061159e91906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061160191906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611640573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166491906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116c791906135f4565b60405163556d6e9f60e01b8152600160048201525f60248201819052604482018a90529192506001600160a01b038a169063556d6e9f906064015b602060405180830381865afa15801561171d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174191906135f4565b90506117e5856001600160a01b031663abfa94466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611782573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117a691906135f4565b6117b890670de0b6b3a76400006136f3565b6117c29085613929565b670de0b6b3a76400006117d5858c613929565b6117df9190613929565b9061318a565b9550858111156118085760405163202f312b60e21b815260040160405180910390fd5b8061181486868961313f565b61181e908861361f565b61182891906136f3565b965050505050509250929050565b61183e6131d2565b604051636525e5f160e01b81527327857f8e0eee20596e7ce5be3901efd663e91e1090636525e5f1906118779086908690600401613550565b6040805180830381865af4158015611891573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ba9190613569565b60405163c661065760e01b81525f600482018190529081906001600160a01b0385169063c661065790602401602060405180830381865afa1580156118fc573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061192091906135c5565b60405163ef8b30f760e01b8152600481018590529091505f906001600160a01b0383169063ef8b30f790602401602060405180830381865afa158015611968573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061198c91906135f4565b90506119988582612dda565b95945050505050565b60405163362d8cb560e11b81526060907327857f8e0eee20596e7ce5be3901efd663e91e1090636c5b196a906119dd9086908690600401613550565b5f60405180830381865af41580156119f7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526107ba9190810190613672565b5f80611a2a8484611531565b915091509250929050565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa158015611a7e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aa291906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ae1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0591906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b6891906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bcb91906135f4565b604051631990812560e31b81526001600160a01b038a1660048201525f6024820181905260016044830152606482018a90529192507327857f8e0eee20596e7ce5be3901efd663e91e109063cc84092890608401602060405180830381865af4158015611410573d5f803e3d5ffd5b60405163c661065760e01b8152600160048201525f9081906001600160a01b0384169063c661065790602401602060405180830381865afa158015611c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ca591906135c5565b90505f816001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0891906135f4565b90505f826001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d6b91906135f4565b90505f610c6c83670de0b6b3a76400006109458960015f6107fc565b604051631e52d01160e21b81526001600160a01b038416600482015260248101839052604481018290525f907327857f8e0eee20596e7ce5be3901efd663e91e109063794b4044906064015b602060405180830381865af4158015611dee573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073891906135f4565b5f80611a2a84846127aa565b604051630de51c1b60e21b81526001600160a01b038416600482015260248101839052604481018290525f907327857f8e0eee20596e7ce5be3901efd663e91e1090633794706c90606401611dd3565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa158015611eb5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ed991906135c5565b60405163fbfc779760e01b8152600481018590526001600160a01b038087166024830152821660448201529091505f907327857f8e0eee20596e7ce5be3901efd663e91e109063fbfc779790606401602060405180830381865af4158015611f43573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f6791906135f4565b90505f611f7482866136f3565b6040516302f6fa9560e11b8152600481018490529091505f906001600160a01b038516906305edf52a90602401602060405180830381865afa158015611fbc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fe091906135f4565b6040805160028082526060820183529293505f92909160208301908036833701905050905082815f81518110612018576120186135e0565b6020026020010181815250508181600181518110612038576120386135e0565b602002602001018181525050610ca78882610fe0565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636c5b196a85856040518363ffffffff1660e01b8152600401612089929190613550565b5f60405180830381865af41580156120a3573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526120ca9190810190613672565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa158015612110573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213491906135c5565b6001600160a01b03166368c1f7f682600181518110612155576121556135e0565b60200260200101516040518263ffffffff1660e01b815260040161217b91815260200190565b602060405180830381865afa158015612196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121ba91906135f4565b815f815181106121cc576121cc6135e0565b6020026020010151610738919061361f565b60405163c661065760e01b81525f600482018190529081906001600160a01b0385169063c661065790602401602060405180830381865afa158015612225573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061224991906135c5565b60405163ef8b30f760e01b8152600481018590529091505f906001600160a01b0383169063ef8b30f790602401602060405180830381865afa158015612291573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122b591906135f4565b9050611998858261101b565b6122c96131d2565b604051631be1eaad60e31b81527327857f8e0eee20596e7ce5be3901efd663e91e109063df0f5568906118779086908690600401613550565b5f807327857f8e0eee20596e7ce5be3901efd663e91e1063df0f556885856040518363ffffffff1660e01b8152600401610540929190613550565b604051639c8d5a5b60e01b81526001600160a01b038416600482015260248101839052600f82900b60448201525f907327857f8e0eee20596e7ce5be3901efd663e91e1090639c8d5a5b90606401611dd3565b60405163c661065760e01b81525f600482018190529081906001600160a01b0385169063c661065790602401602060405180830381865afa1580156123d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123fb91906135c5565b60405163ef8b30f760e01b8152600481018590529091505f906001600160a01b0383169063ef8b30f790602401602060405180830381865afa158015612443573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061246791906135f4565b90506119988582611e6e565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636525e5f185856040518363ffffffff1660e01b81526004016124ae929190613550565b6040805180830381865af41580156124c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124ec9190613569565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa158015612532573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061255691906135c5565b6001600160a01b03166368c1f7f682600160200201516040518263ffffffff1660e01b815260040161258a91815260200190565b602060405180830381865afa1580156125a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125c991906135f4565b8151610738919061361f565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa15801561261e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061264291906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa158015612681573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126a591906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126e4573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061270891906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b91906135f4565b604051635e0d443f60e01b8152600160048201525f60248201819052604482018a90529192506001600160a01b038a1690635e0d443f90606401611702565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa1580156127f3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061281791906135c5565b6040516302f6fa9560e11b8152600481018690529091505f906001600160a01b038316906305edf52a90602401602060405180830381865afa15801561285f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288391906135f4565b90505f6128908688610b1f565b60405163c661065760e01b81525f600482018190529192506128c5906001600160a01b038a169063c661065790602401610dcc565b90505f5b60ff811015612984576128de6103e88361371a565b6128ec83610e3287876130a6565b10612984575f6128fc8a86611531565b5090505f61290a8b86611531565b5090505f6129178b6130dc565b612920846130dc565b61292a919061372d565b90505f6129368c6130dc565b61293f846130dc565b612949919061372d565b905080820361295b5750505050612984565b5f612969610eb9848461372d565b97985061297d94508593506137ae92505050565b90506128c9565b5061298f8383613131565b95505f61299c8988611531565b9650905087811115610f9057620f42405f5b60ff811015610f8d576129c5610f5d6001846136f3565b98506129d18b8a611531565b9850925089831115610f8d576129e6816137ae565b90506129ae565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636c5b196a85856040518363ffffffff1660e01b8152600401612a28929190613550565b5f60405180830381865af4158015612a42573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612a699190810190613672565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa158015612aaf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ad391906135c5565b6001600160a01b0316634cdad50682600181518110612af457612af46135e0565b60200260200101516040518263ffffffff1660e01b8152600401612b1a91815260200190565b602060405180830381865afa158015612b35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b5991906135f4565b60405163c661065760e01b81525f60048201526001600160a01b0386169063c661065790602401602060405180830381865afa158015612b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bbf91906135c5565b6001600160a01b0316634cdad506835f81518110612bdf57612bdf6135e0565b60200260200101516040518263ffffffff1660e01b81526004016106ef91815260200190565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa158015612c4e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c7291906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cb1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d14573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d3891906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d77573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d9b91906135f4565b6040516333ef816560e11b81525f6004820181905260016024830152604482018a90529192506001600160a01b038a16906367df02ca906064016113f5565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa158015612e21573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e4591906135c5565b60405163fbfc779760e01b8152600481018590526001600160a01b038087166024830152821660448201529091505f907327857f8e0eee20596e7ce5be3901efd663e91e109063fbfc779790606401602060405180830381865af4158015612eaf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ed391906135f4565b90505f612ee082866136f3565b6040516302f6fa9560e11b8152600481018490529091505f906001600160a01b038516906305edf52a90602401602060405180830381865afa158015612f28573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f4c91906135f4565b905061121987604051806040016040528085815260200184815250610740565b5f807327857f8e0eee20596e7ce5be3901efd663e91e1063df0f556885856040518363ffffffff1660e01b81526004016124ae929190613550565b5f610caf826001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de7573d5f803e3d5ffd5b5f838302815f1985870982811083820303915050805f0361301b5783828161301157613011613706565b04925050506107ba565b80841161303b5760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f8183116130b457816107ba565b5090919050565b5f8183116130d2576130cd83836136f3565b6107ba565b6107ba82846136f3565b5f6001600160ff1b038211156131085760405163123baf0360e11b8152600481018390526024016109e9565b5090565b5f8082121561310857604051635467221960e11b8152600481018390526024016109e9565b5f8183106130b457816107ba565b604051633676633960e21b81525f906001600160a01b0385169063d9d98ce49061316f9086908690600401613550565b602060405180830381865afa158015611dee573d5f803e3d5ffd5b5f815f036131a35761319c828461371a565b9050610caf565b82156131ca57816131b56001856136f3565b6131bf919061371a565b6130cd90600161361f565b505f92915050565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b0381168114613204575f80fd5b50565b5f8060408385031215613218575f80fd5b8235613223816131f0565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff8111828210171561326857613268613231565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561329757613297613231565b604052919050565b5f80606083850312156132b0575f80fd5b82356132bb816131f0565b91506020603f840185136132cd575f80fd5b6132d5613245565b8060608601878111156132e6575f80fd5b8387015b8181101561330157803584529284019284016132ea565b509497909650945050505050565b8035600f81900b8114613320575f80fd5b919050565b5f805f60608486031215613337575f80fd5b8335613342816131f0565b92506133506020850161330f565b915061335e6040850161330f565b90509250925092565b5f805f60608486031215613379575f80fd5b8335613384816131f0565b95602085013595506040909401359392505050565b5f80604083850312156133aa575f80fd5b8235915060208301356133bc816131f0565b809150509250929050565b5f67ffffffffffffffff8211156133e0576133e0613231565b5060051b60200190565b5f80604083850312156133fb575f80fd5b8235613406816131f0565b915060208381013567ffffffffffffffff811115613422575f80fd5b8401601f81018613613432575f80fd5b8035613445613440826133c7565b61326e565b81815260059190911b82018301908381019088831115613463575f80fd5b928401925b8284101561348157833582529284019290840190613468565b80955050505050509250929050565b5f602082840312156134a0575f80fd5b81356107ba816131f0565b6040810181835f5b60028110156134d25781518352602092830192909101906001016134b3565b50505092915050565b602080825282518282018190525f9190848201906040850190845b81811015613512578351835292840192918401916001016134f6565b50909695505050505050565b5f805f60608486031215613530575f80fd5b833561353b816131f0565b92506020840135915061335e6040850161330f565b6001600160a01b03929092168252602082015260400190565b5f60408284031215613579575f80fd5b82601f830112613587575f80fd5b61358f613245565b8060408401858111156135a0575f80fd5b845b818110156135ba5780518452602093840193016135a2565b509095945050505050565b5f602082840312156135d5575f80fd5b81516107ba816131f0565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613604575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610caf57610caf61360b565b6001600160a01b0383168152606081016020808301845f5b60028110156136675781518352918301919083019060010161364a565b505050509392505050565b5f6020808385031215613683575f80fd5b825167ffffffffffffffff811115613699575f80fd5b8301601f810185136136a9575f80fd5b80516136b7613440826133c7565b81815260059190911b820183019083810190878311156136d5575f80fd5b928401925b82841015611219578351825292840192908401906136da565b81810381811115610caf57610caf61360b565b634e487b7160e01b5f52601260045260245ffd5b5f8261372857613728613706565b500490565b8181035f83128015838313168383128216171561374c5761374c61360b565b5092915050565b8082025f8212600160ff1b8414161561376e5761376e61360b565b8181058314821517610caf57610caf61360b565b5f8261379057613790613706565b600160ff1b82145f19841416156137a9576137a961360b565b500590565b5f600182016137bf576137bf61360b565b5060010190565b6001600160a01b03831681526040602080830182905283519183018290525f9184820191906060850190845b8181101561380e578451835293830193918301916001016137f2565b5090979650505050505050565b5f6020828403121561382b575f80fd5b815160ff811681146107ba575f80fd5b600181815b8085111561387557815f190482111561385b5761385b61360b565b8085161561386857918102915b93841c9390800290613840565b509250929050565b5f8261388b57506001610caf565b8161389757505f610caf565b81600181146138ad57600281146138b7576138d3565b6001915050610caf565b60ff8411156138c8576138c861360b565b50506001821b610caf565b5060208310610133831016604e8410600b84101617156138f6575081810a610caf565b613900838361383b565b805f19048211156139135761391361360b565b029392505050565b5f6107ba60ff84168361387d565b8082028115828204841417610caf57610caf61360b56fea2646970667358221220be7bdbbd9b7d4ca835d1e6ae5f27e74b08e89cba69ed9ac3e791696484900e0d64736f6c63430008140033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610213575f3560e01c8063794b40441161011f578063a0f3b821116100a9578063b688026d11610079578063b688026d146104a6578063b775c261146104b9578063d0a3fcb4146104cc578063f829c8f7146104df578063f8fc815c146104f2575f80fd5b8063a0f3b8211461045a578063a3284ec81461046d578063a9982ee814610480578063b03ae38114610493575f80fd5b806386b3b868116100ef57806386b3b868146103fb57806388a312e21461040e57806394e5ef67146104215780639b88c6db146104345780639c8d5a5b14610447575f80fd5b8063794b4044146103af5780637c3bdb28146103c2578063800738e9146103d557806384943214146103e8575f80fd5b80635e16f1e9116101a05780636b0426cb116101705780636b0426cb146103435780636c5b196a14610356578063719fbb27146103765780637441de6a1461038957806378c090931461039c575f80fd5b80635e16f1e9146102ea5780635fa5a497146102fd578063625aefd2146103105780636525e5f114610323575f80fd5b80632271e1f8116101e65780632271e1f8146102765780632fee2f091461028957806331922b4b1461029c5780634346b24f146102c457806344cee8f7146102d7575f80fd5b80630d029aa5146102175780630f9c83281461023d578063102c05e51461025057806314633b6814610263575b5f80fd5b61022a610225366004613207565b610505565b6040519081526020015b60405180910390f35b61022a61024b36600461329f565b610740565b61022a61025e36600461329f565b6107c1565b61022a610271366004613325565b6107fc565b61022a610284366004613367565b6109f2565b61022a610297366004613399565b610b1f565b6102af6102aa366004613207565b610cb5565b60408051928352602083019190915201610234565b61022a6102d23660046133ea565b610fe0565b61022a6102e5366004613207565b61101b565b6102af6102f8366004613207565b611224565b61022a61030b366004613490565b6114c5565b6102af61031e366004613207565b611531565b610336610331366004613207565b611836565b60405161023491906134ab565b61022a610351366004613207565b6118b5565b610369610364366004613207565b6119a1565b60405161023491906134db565b6102af610384366004613207565b611a1e565b6102af610397366004613207565b611a35565b61022a6103aa366004613399565b611c3a565b61022a6103bd366004613367565b611d87565b6102af6103d0366004613207565b611e12565b61022a6103e3366004613367565b611e1e565b61022a6103f6366004613207565b611e6e565b61022a610409366004613207565b61204e565b61022a61041c366004613207565b6121de565b61033661042f366004613207565b6122c1565b61022a610442366004613207565b612302565b61022a61045536600461351e565b61233d565b61022a610468366004613207565b612390565b61022a61047b366004613207565b612473565b6102af61048e366004613207565b6125d5565b6102af6104a1366004613207565b6127aa565b61022a6104b4366004613207565b6129ed565b6102af6104c7366004613207565b612c05565b61022a6104da366004613207565b612dda565b61022a6104ed366004613207565b612f6c565b61022a610500366004613490565b612fa7565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636525e5f185856040518363ffffffff1660e01b8152600401610540929190613550565b6040805180830381865af415801561055a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061057e9190613569565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa1580156105c4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e891906135c5565b6001600160a01b0316634cdad50682600160200201516040518263ffffffff1660e01b815260040161061c91815260200190565b602060405180830381865afa158015610637573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061065b91906135f4565b60405163c661065760e01b81525f60048201526001600160a01b0386169063c661065790602401602060405180830381865afa15801561069d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106c191906135c5565b825160405163266d6a8360e11b815260048101919091526001600160a01b039190911690634cdad506906024015b602060405180830381865afa15801561070a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061072e91906135f4565b610738919061361f565b949350505050565b6040516301f3906560e31b81525f907327857f8e0eee20596e7ce5be3901efd663e91e1090630f9c83289061077b9086908690600401613632565b602060405180830381865af4158015610796573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ba91906135f4565b9392505050565b6040516370b3fe7560e01b81525f907327857f8e0eee20596e7ce5be3901efd663e91e10906370b3fe759061077b9086908690600401613632565b604051631c98d5a960e11b81525f600482018190529081906001600160a01b03861690633931ab5290602401602060405180830381865afa158015610843573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061086791906135f4565b90505f856001600160a01b031663fd0684b16040518163ffffffff1660e01b81526004015f60405180830381865afa1580156108a5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526108cc9190810190613672565b905084600f0b5f1480156108e3575083600f0b6001145b156109565761094c670de0b6b3a764000083610945670de0b6b3a764000085600181518110610914576109146135e0565b6020026020010151865f8151811061092e5761092e6135e0565b6020026020010151612fe79092919063ffffffff16565b9190612fe7565b92506107ba915050565b84600f0b600114801561096b575083600f0b5f145b156109b85761094c81600181518110610986576109866135e0565b6020026020010151825f815181106109a0576109a06135e0565b602002602001015184612fe79092919063ffffffff16565b60405163175ebd2b60e11b81526fffffffffffffffffffffffffffffffff8087166004830152851660248201526044015b60405180910390fd5b5f82158015610a015750816001145b15610a8957610a82670de0b6b3a7640000856001600160a01b031663c146bf946040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a4e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7291906135f4565b670de0b6b3a76400009190612fe7565b90506107ba565b826001148015610a97575081155b15610afc57836001600160a01b031663c146bf946040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ad8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a8291906135f4565b60405163175ebd2b60e11b815260048101849052602481018390526044016109e9565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0384169063c661065790602401602060405180830381865afa158015610b66573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b8a91906135c5565b90505f816001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bed91906135f4565b90505f826001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c2c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5091906135f4565b90505f610c6c83670de0b6b3a76400006109458960015f6109f2565b905081811115610c8f5760405163202f312b60e21b815260040160405180910390fd5b5f610c9a82846136f3565b9050610ca7888583612fe7565b955050505050505b92915050565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa158015610cfe573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d2291906135c5565b6040516302f6fa9560e11b8152600481018690529091505f906001600160a01b038316906305edf52a90602401602060405180830381865afa158015610d6a573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d8e91906135f4565b90505f610d9b8688611c3a565b60405163c661065760e01b81525f60048201819052919250610e0b906001600160a01b038a169063c6610657906024015b602060405180830381865afa158015610de7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061030b91906135c5565b90505f5b60ff811015610f1c57610e246103e88361371a565b610e3c83610e3287876130a6565b61094588886130bb565b10610f1c575f610e4c8a866125d5565b5090505f610e5a8b866125d5565b5090505f610e678b6130dc565b610e70846130dc565b610e7a919061372d565b90505f610e868c6130dc565b610e8f846130dc565b610e99919061372d565b9050808203610eab5750505050610f1c565b5f610f01610eb9848461372d565b610ec28b6130dc565b610ecb8b6130dc565b610ed5919061372d565b610edf9085613753565b610ee99190613782565b610ef28a6130dc565b610efc919061372d565b61310c565b979850610f1594508593506137ae92505050565b9050610e0f565b50610f278383613131565b95505f610f3489886125d5565b9650905087811115610f9057620f42405f5b60ff811015610f8d57610f65610f5d6001846136f3565b8a9084612fe7565b9850610f718b8a6125d5565b9850925089831115610f8d57610f86816137ae565b9050610f46565b50505b87811180610fb65750610fa56103e88361371a565b610fb4838a6109458c866130bb565b115b15610fd457604051635aae0c9960e11b815260040160405180910390fd5b50505050509250929050565b604051634346b24f60e01b81525f907327857f8e0eee20596e7ce5be3901efd663e91e1090634346b24f9061077b90869086906004016137c6565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa158015611062573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108691906135c5565b60405163fbfc779760e01b8152600481018590526001600160a01b038087166024830152821660448201529091505f907327857f8e0eee20596e7ce5be3901efd663e91e109063fbfc779790606401602060405180830381865af41580156110f0573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061111491906135f4565b90505f61112182866136f3565b6040516302f6fa9560e11b8152600481018490529091505f906001600160a01b038516906305edf52a90602401602060405180830381865afa158015611169573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061118d91906135f4565b6040805180820182528481526020810183905290516370b3fe7560e01b81529192507327857f8e0eee20596e7ce5be3901efd663e91e10916370b3fe75916111da918b9190600401613632565b602060405180830381865af41580156111f5573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061121991906135f4565b979650505050505050565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa15801561126d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061129191906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112f491906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611333573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135791906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611396573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113ba91906135f4565b604051631bf69d3d60e11b81525f6004820181905260016024830152604482018a90529192506001600160a01b038a16906337ed3a7a906064015b602060405180830381865afa158015611410573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061143491906135f4565b90505f611442898486612fe7565b90505f61145087878561313f565b9050818311156114735760405163202f312b60e21b815260040160405180910390fd5b8161147e828561361f565b111561149d57604051638a7ceb6f60e01b815260040160405180910390fd5b5f816114a985856136f3565b6114b391906136f3565b9c939b50929950505050505050505050565b5f816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611502573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611526919061381b565b610caf90600a61391b565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa15801561157a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061159e91906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115dd573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061160191906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611640573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166491906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116a3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116c791906135f4565b60405163556d6e9f60e01b8152600160048201525f60248201819052604482018a90529192506001600160a01b038a169063556d6e9f906064015b602060405180830381865afa15801561171d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061174191906135f4565b90506117e5856001600160a01b031663abfa94466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611782573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117a691906135f4565b6117b890670de0b6b3a76400006136f3565b6117c29085613929565b670de0b6b3a76400006117d5858c613929565b6117df9190613929565b9061318a565b9550858111156118085760405163202f312b60e21b815260040160405180910390fd5b8061181486868961313f565b61181e908861361f565b61182891906136f3565b965050505050509250929050565b61183e6131d2565b604051636525e5f160e01b81527327857f8e0eee20596e7ce5be3901efd663e91e1090636525e5f1906118779086908690600401613550565b6040805180830381865af4158015611891573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ba9190613569565b60405163c661065760e01b81525f600482018190529081906001600160a01b0385169063c661065790602401602060405180830381865afa1580156118fc573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061192091906135c5565b60405163ef8b30f760e01b8152600481018590529091505f906001600160a01b0383169063ef8b30f790602401602060405180830381865afa158015611968573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061198c91906135f4565b90506119988582612dda565b95945050505050565b60405163362d8cb560e11b81526060907327857f8e0eee20596e7ce5be3901efd663e91e1090636c5b196a906119dd9086908690600401613550565b5f60405180830381865af41580156119f7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526107ba9190810190613672565b5f80611a2a8484611531565b915091509250929050565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa158015611a7e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aa291906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ae1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b0591906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b6891906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ba7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bcb91906135f4565b604051631990812560e31b81526001600160a01b038a1660048201525f6024820181905260016044830152606482018a90529192507327857f8e0eee20596e7ce5be3901efd663e91e109063cc84092890608401602060405180830381865af4158015611410573d5f803e3d5ffd5b60405163c661065760e01b8152600160048201525f9081906001600160a01b0384169063c661065790602401602060405180830381865afa158015611c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ca591906135c5565b90505f816001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0891906135f4565b90505f826001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d47573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d6b91906135f4565b90505f610c6c83670de0b6b3a76400006109458960015f6107fc565b604051631e52d01160e21b81526001600160a01b038416600482015260248101839052604481018290525f907327857f8e0eee20596e7ce5be3901efd663e91e109063794b4044906064015b602060405180830381865af4158015611dee573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073891906135f4565b5f80611a2a84846127aa565b604051630de51c1b60e21b81526001600160a01b038416600482015260248101839052604481018290525f907327857f8e0eee20596e7ce5be3901efd663e91e1090633794706c90606401611dd3565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa158015611eb5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ed991906135c5565b60405163fbfc779760e01b8152600481018590526001600160a01b038087166024830152821660448201529091505f907327857f8e0eee20596e7ce5be3901efd663e91e109063fbfc779790606401602060405180830381865af4158015611f43573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f6791906135f4565b90505f611f7482866136f3565b6040516302f6fa9560e11b8152600481018490529091505f906001600160a01b038516906305edf52a90602401602060405180830381865afa158015611fbc573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fe091906135f4565b6040805160028082526060820183529293505f92909160208301908036833701905050905082815f81518110612018576120186135e0565b6020026020010181815250508181600181518110612038576120386135e0565b602002602001018181525050610ca78882610fe0565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636c5b196a85856040518363ffffffff1660e01b8152600401612089929190613550565b5f60405180830381865af41580156120a3573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526120ca9190810190613672565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa158015612110573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061213491906135c5565b6001600160a01b03166368c1f7f682600181518110612155576121556135e0565b60200260200101516040518263ffffffff1660e01b815260040161217b91815260200190565b602060405180830381865afa158015612196573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121ba91906135f4565b815f815181106121cc576121cc6135e0565b6020026020010151610738919061361f565b60405163c661065760e01b81525f600482018190529081906001600160a01b0385169063c661065790602401602060405180830381865afa158015612225573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061224991906135c5565b60405163ef8b30f760e01b8152600481018590529091505f906001600160a01b0383169063ef8b30f790602401602060405180830381865afa158015612291573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122b591906135f4565b9050611998858261101b565b6122c96131d2565b604051631be1eaad60e31b81527327857f8e0eee20596e7ce5be3901efd663e91e109063df0f5568906118779086908690600401613550565b5f807327857f8e0eee20596e7ce5be3901efd663e91e1063df0f556885856040518363ffffffff1660e01b8152600401610540929190613550565b604051639c8d5a5b60e01b81526001600160a01b038416600482015260248101839052600f82900b60448201525f907327857f8e0eee20596e7ce5be3901efd663e91e1090639c8d5a5b90606401611dd3565b60405163c661065760e01b81525f600482018190529081906001600160a01b0385169063c661065790602401602060405180830381865afa1580156123d7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123fb91906135c5565b60405163ef8b30f760e01b8152600481018590529091505f906001600160a01b0383169063ef8b30f790602401602060405180830381865afa158015612443573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061246791906135f4565b90506119988582611e6e565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636525e5f185856040518363ffffffff1660e01b81526004016124ae929190613550565b6040805180830381865af41580156124c8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124ec9190613569565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa158015612532573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061255691906135c5565b6001600160a01b03166368c1f7f682600160200201516040518263ffffffff1660e01b815260040161258a91815260200190565b602060405180830381865afa1580156125a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906125c991906135f4565b8151610738919061361f565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa15801561261e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061264291906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa158015612681573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126a591906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa1580156126e4573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061270891906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b91906135f4565b604051635e0d443f60e01b8152600160048201525f60248201819052604482018a90529192506001600160a01b038a1690635e0d443f90606401611702565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa1580156127f3573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061281791906135c5565b6040516302f6fa9560e11b8152600481018690529091505f906001600160a01b038316906305edf52a90602401602060405180830381865afa15801561285f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288391906135f4565b90505f6128908688610b1f565b60405163c661065760e01b81525f600482018190529192506128c5906001600160a01b038a169063c661065790602401610dcc565b90505f5b60ff811015612984576128de6103e88361371a565b6128ec83610e3287876130a6565b10612984575f6128fc8a86611531565b5090505f61290a8b86611531565b5090505f6129178b6130dc565b612920846130dc565b61292a919061372d565b90505f6129368c6130dc565b61293f846130dc565b612949919061372d565b905080820361295b5750505050612984565b5f612969610eb9848461372d565b97985061297d94508593506137ae92505050565b90506128c9565b5061298f8383613131565b95505f61299c8988611531565b9650905087811115610f9057620f42405f5b60ff811015610f8d576129c5610f5d6001846136f3565b98506129d18b8a611531565b9850925089831115610f8d576129e6816137ae565b90506129ae565b5f807327857f8e0eee20596e7ce5be3901efd663e91e10636c5b196a85856040518363ffffffff1660e01b8152600401612a28929190613550565b5f60405180830381865af4158015612a42573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612a699190810190613672565b60405163c661065760e01b8152600160048201529091506001600160a01b0385169063c661065790602401602060405180830381865afa158015612aaf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ad391906135c5565b6001600160a01b0316634cdad50682600181518110612af457612af46135e0565b60200260200101516040518263ffffffff1660e01b8152600401612b1a91815260200190565b602060405180830381865afa158015612b35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b5991906135f4565b60405163c661065760e01b81525f60048201526001600160a01b0386169063c661065790602401602060405180830381865afa158015612b9b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bbf91906135c5565b6001600160a01b0316634cdad506835f81518110612bdf57612bdf6135e0565b60200260200101516040518263ffffffff1660e01b81526004016106ef91815260200190565b60405163c661065760e01b8152600160048201525f90819081906001600160a01b0386169063c661065790602401602060405180830381865afa158015612c4e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c7291906135c5565b90505f816001600160a01b031663c644fe946040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cb1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cd591906135c5565b90505f826001600160a01b031663efd98dc26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d14573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d3891906135f4565b90505f836001600160a01b031663a1c5b3e16040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d77573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d9b91906135f4565b6040516333ef816560e11b81525f6004820181905260016024830152604482018a90529192506001600160a01b038a16906367df02ca906064016113f5565b60405163c661065760e01b8152600160048201525f9081906001600160a01b0385169063c661065790602401602060405180830381865afa158015612e21573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e4591906135c5565b60405163fbfc779760e01b8152600481018590526001600160a01b038087166024830152821660448201529091505f907327857f8e0eee20596e7ce5be3901efd663e91e109063fbfc779790606401602060405180830381865af4158015612eaf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ed391906135f4565b90505f612ee082866136f3565b6040516302f6fa9560e11b8152600481018490529091505f906001600160a01b038516906305edf52a90602401602060405180830381865afa158015612f28573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f4c91906135f4565b905061121987604051806040016040528085815260200184815250610740565b5f807327857f8e0eee20596e7ce5be3901efd663e91e1063df0f556885856040518363ffffffff1660e01b81526004016124ae929190613550565b5f610caf826001600160a01b0316636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015610de7573d5f803e3d5ffd5b5f838302815f1985870982811083820303915050805f0361301b5783828161301157613011613706565b04925050506107ba565b80841161303b5760405163227bc15360e01b815260040160405180910390fd5b5f848688095f868103871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103029181900381900460010186841190950394909402919094039290920491909117919091029150509392505050565b5f8183116130b457816107ba565b5090919050565b5f8183116130d2576130cd83836136f3565b6107ba565b6107ba82846136f3565b5f6001600160ff1b038211156131085760405163123baf0360e11b8152600481018390526024016109e9565b5090565b5f8082121561310857604051635467221960e11b8152600481018390526024016109e9565b5f8183106130b457816107ba565b604051633676633960e21b81525f906001600160a01b0385169063d9d98ce49061316f9086908690600401613550565b602060405180830381865afa158015611dee573d5f803e3d5ffd5b5f815f036131a35761319c828461371a565b9050610caf565b82156131ca57816131b56001856136f3565b6131bf919061371a565b6130cd90600161361f565b505f92915050565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b0381168114613204575f80fd5b50565b5f8060408385031215613218575f80fd5b8235613223816131f0565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff8111828210171561326857613268613231565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561329757613297613231565b604052919050565b5f80606083850312156132b0575f80fd5b82356132bb816131f0565b91506020603f840185136132cd575f80fd5b6132d5613245565b8060608601878111156132e6575f80fd5b8387015b8181101561330157803584529284019284016132ea565b509497909650945050505050565b8035600f81900b8114613320575f80fd5b919050565b5f805f60608486031215613337575f80fd5b8335613342816131f0565b92506133506020850161330f565b915061335e6040850161330f565b90509250925092565b5f805f60608486031215613379575f80fd5b8335613384816131f0565b95602085013595506040909401359392505050565b5f80604083850312156133aa575f80fd5b8235915060208301356133bc816131f0565b809150509250929050565b5f67ffffffffffffffff8211156133e0576133e0613231565b5060051b60200190565b5f80604083850312156133fb575f80fd5b8235613406816131f0565b915060208381013567ffffffffffffffff811115613422575f80fd5b8401601f81018613613432575f80fd5b8035613445613440826133c7565b61326e565b81815260059190911b82018301908381019088831115613463575f80fd5b928401925b8284101561348157833582529284019290840190613468565b80955050505050509250929050565b5f602082840312156134a0575f80fd5b81356107ba816131f0565b6040810181835f5b60028110156134d25781518352602092830192909101906001016134b3565b50505092915050565b602080825282518282018190525f9190848201906040850190845b81811015613512578351835292840192918401916001016134f6565b50909695505050505050565b5f805f60608486031215613530575f80fd5b833561353b816131f0565b92506020840135915061335e6040850161330f565b6001600160a01b03929092168252602082015260400190565b5f60408284031215613579575f80fd5b82601f830112613587575f80fd5b61358f613245565b8060408401858111156135a0575f80fd5b845b818110156135ba5780518452602093840193016135a2565b509095945050505050565b5f602082840312156135d5575f80fd5b81516107ba816131f0565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215613604575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115610caf57610caf61360b565b6001600160a01b0383168152606081016020808301845f5b60028110156136675781518352918301919083019060010161364a565b505050509392505050565b5f6020808385031215613683575f80fd5b825167ffffffffffffffff811115613699575f80fd5b8301601f810185136136a9575f80fd5b80516136b7613440826133c7565b81815260059190911b820183019083810190878311156136d5575f80fd5b928401925b82841015611219578351825292840192908401906136da565b81810381811115610caf57610caf61360b565b634e487b7160e01b5f52601260045260245ffd5b5f8261372857613728613706565b500490565b8181035f83128015838313168383128216171561374c5761374c61360b565b5092915050565b8082025f8212600160ff1b8414161561376e5761376e61360b565b8181058314821517610caf57610caf61360b565b5f8261379057613790613706565b600160ff1b82145f19841416156137a9576137a961360b565b500590565b5f600182016137bf576137bf61360b565b5060010190565b6001600160a01b03831681526040602080830182905283519183018290525f9184820191906060850190845b8181101561380e578451835293830193918301916001016137f2565b5090979650505050505050565b5f6020828403121561382b575f80fd5b815160ff811681146107ba575f80fd5b600181815b8085111561387557815f190482111561385b5761385b61360b565b8085161561386857918102915b93841c9390800290613840565b509250929050565b5f8261388b57506001610caf565b8161389757505f610caf565b81600181146138ad57600281146138b7576138d3565b6001915050610caf565b60ff8411156138c8576138c861360b565b50506001821b610caf565b5060208310610133831016604e8410600b84101617156138f6575081810a610caf565b613900838361383b565b805f19048211156139135761391361360b565b029392505050565b5f6107ba60ff84168361387d565b8082028115828204841417610caf57610caf61360b56fea2646970667358221220be7bdbbd9b7d4ca835d1e6ae5f27e74b08e89cba69ed9ac3e791696484900e0d64736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.