Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 26403488 | 421 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
AerodromeStandardModulePrivate
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
import {IArrakisLPModule} from "../interfaces/IArrakisLPModule.sol";
import {IArrakisLPModulePrivate} from
"../interfaces/IArrakisLPModulePrivate.sol";
import {IArrakisMetaVault} from "../interfaces/IArrakisMetaVault.sol";
import {IAerodromeStandardModulePrivate} from
"../interfaces/IAerodromeStandardModulePrivate.sol";
import {IArrakisLPModuleID} from
"../interfaces/IArrakisLPModuleID.sol";
import {IUniswapV3Factory} from "../interfaces/IUniswapV3Factory.sol";
import {INonfungiblePositionManager} from
"../interfaces/INonfungiblePositionManager.sol";
import {IVoter} from "../interfaces/IVoter.sol";
import {ICLGauge} from "../interfaces/ICLGauge.sol";
import {IUniswapV3Pool} from "../interfaces/IUniswapV3Pool.sol";
import {IOracleWrapper} from "../interfaces/IOracleWrapper.sol";
import {IOwnable} from "../interfaces/IOwnable.sol";
import {IGuardian} from "../interfaces/IGuardian.sol";
import {
TEN_PERCENT,
NATIVE_COIN,
BASE,
PIPS
} from "../constants/CArrakis.sol";
import {
RebalanceParams,
ModifyPosition
} from "../structs/SUniswapV3.sol";
import {FullMath} from "@v3-lib-0.8/contracts/FullMath.sol";
import {LiquidityAmounts} from
"@v3-lib-0.8/contracts/LiquidityAmounts.sol";
import {TickMath} from "@v3-lib-0.8/contracts/TickMath.sol";
import {EnumerableSet} from
"@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {PausableUpgradeable} from
"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from
"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {SafeERC20} from
"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeCast} from
"@openzeppelin/contracts/utils/math/SafeCast.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {IERC721Receiver} from
"@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC20Metadata} from
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
contract AerodromeStandardModulePrivate is
IArrakisLPModule,
IArrakisLPModulePrivate,
IAerodromeStandardModulePrivate,
IArrakisLPModuleID,
IERC721Receiver,
PausableUpgradeable,
ReentrancyGuardUpgradeable
{
using SafeERC20 for IERC20Metadata;
using EnumerableSet for EnumerableSet.UintSet;
using Address for address;
// #region constant internal variables.
/// @dev id = keccak256(abi.encode("AerodromeStandardModulePrivate"))
/// @inheritdoc IArrakisLPModuleID
bytes32 public constant id =
0x491defc0794897991a8e5e9fa49dcbed24fe84ee079750b1db3f4df77fb17cb5;
/// @inheritdoc IAerodromeStandardModulePrivate
address public constant AERO =
0x940181a94A35A4569E4529A3CDfB74e38FD98631;
// #endregion constant internal variables.
// #region immutable internal variables.
address internal immutable _guardian;
// #endregion immutable internal variables.
// #region immutable state variables.
/// @inheritdoc IAerodromeStandardModulePrivate
INonfungiblePositionManager public immutable nftPositionManager;
/// @inheritdoc IAerodromeStandardModulePrivate
IUniswapV3Factory public immutable factory;
/// @inheritdoc IAerodromeStandardModulePrivate
IVoter public immutable voter;
// #endregion immutable state variables.
/// @inheritdoc IArrakisLPModule
IArrakisMetaVault public metaVault;
/// @inheritdoc IArrakisLPModule
IERC20Metadata public token0;
/// @inheritdoc IArrakisLPModule
IERC20Metadata public token1;
/// @inheritdoc IAerodromeStandardModulePrivate
IOracleWrapper public oracle;
/// @inheritdoc IArrakisLPModule
uint256 public managerFeePIPS;
/// @inheritdoc IAerodromeStandardModulePrivate
uint24 public maxSlippage;
/// @inheritdoc IAerodromeStandardModulePrivate
address public aeroReceiver;
/// @inheritdoc IAerodromeStandardModulePrivate
address public pool;
/// @inheritdoc IAerodromeStandardModulePrivate
address public gauge;
// #region internal state variables.
EnumerableSet.UintSet internal _tokenIds;
uint256 internal _aeroManagerBalance;
// #endregion internal state variables.
// #region modifiers.
modifier onlyManager() {
address manager = metaVault.manager();
if (manager != msg.sender) {
revert OnlyManager(msg.sender, manager);
}
_;
}
modifier onlyMetaVault() {
address metaVaultAddr = address(metaVault);
if (metaVaultAddr != msg.sender) {
revert OnlyMetaVault(msg.sender, metaVaultAddr);
}
_;
}
modifier onlyGuardian() {
address pauser = IGuardian(_guardian).pauser();
if (pauser != msg.sender) revert OnlyGuardian();
_;
}
modifier onlyMetaVaultOwner() {
if (msg.sender != IOwnable(address(metaVault)).owner()) {
revert OnlyMetaVaultOwner();
}
_;
}
// #endregion modifiers.
constructor(
address nftPositionManager_,
address factory_,
address voter_,
address guardian_
) {
if (
nftPositionManager_ == address(0)
|| factory_ == address(0) || voter_ == address(0)
|| guardian_ == address(0)
) {
revert AddressZero();
}
nftPositionManager =
INonfungiblePositionManager(nftPositionManager_);
factory = IUniswapV3Factory(factory_);
voter = IVoter(voter_);
_guardian = guardian_;
_disableInitializers();
}
// #region ERC721 receiver.
/// @inheritdoc IERC721Receiver
function onERC721Received(
address,
address,
uint256,
bytes calldata
) external returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
// #endregion ERC721 receiver.
// #region guardian functions.
/// @inheritdoc IArrakisLPModule
function pause() external whenNotPaused onlyGuardian {
_pause();
}
/// @inheritdoc IArrakisLPModule
function unpause() external whenPaused onlyGuardian {
_unpause();
}
// #endregion guardian functions.
// #region initialize functions.
/// @inheritdoc IAerodromeStandardModulePrivate
function initialize(
IOracleWrapper oracle_,
uint24 maxSlippage_,
address aeroReceiver_,
int24 tickSpacing_,
address metaVault_
) external initializer {
// #region checks.
if (
metaVault_ == address(0) || address(oracle_) == address(0)
|| aeroReceiver_ == address(0)
) revert AddressZero();
if (maxSlippage_ > TEN_PERCENT) {
revert MaxSlippageGtTenPercent();
}
// #endregion checks.
metaVault = IArrakisMetaVault(metaVault_);
oracle = oracle_;
maxSlippage = maxSlippage_;
aeroReceiver = aeroReceiver_;
address _token0 = IArrakisMetaVault(metaVault_).token0();
address _token1 = IArrakisMetaVault(metaVault_).token1();
if (_token0 == NATIVE_COIN || _token1 == NATIVE_COIN) {
revert NativeCoinNotSupported();
}
if (_token0 == AERO || _token1 == AERO) {
revert AEROTokenNotSupported();
}
address _pool =
factory.getPool(_token0, _token1, tickSpacing_);
if (_pool == address(0)) {
revert PoolNotFound();
}
address _gauge = voter.gauges(_pool);
if (!voter.isAlive(_gauge)) {
revert GaugeKilled();
}
pool = _pool;
gauge = _gauge;
token0 = IERC20Metadata(_token0);
token1 = IERC20Metadata(_token1);
__ReentrancyGuard_init();
__Pausable_init();
}
/// @inheritdoc IArrakisLPModule
function initializePosition(
bytes calldata data_
) external {
/// @dev left over will sit on the module.
}
// #endregion initialize functions.
// #region rfq system.
/// @inheritdoc IAerodromeStandardModulePrivate
function approve(
address spender_,
uint256 amount0_,
uint256 amount1_
) external nonReentrant whenNotPaused onlyMetaVaultOwner {
IERC20Metadata _token0 = token0;
IERC20Metadata _token1 = token1;
_token0.forceApprove(spender_, amount0_);
_token1.forceApprove(spender_, amount1_);
emit LogApproval(spender_, amount0_, amount1_);
}
// #endregion rfq system.
/// @inheritdoc IArrakisLPModulePrivate
function fund(
address depositor_,
uint256 amount0_,
uint256 amount1_
) external payable nonReentrant onlyMetaVault whenNotPaused {
if (msg.value != 0) {
revert NativeCoinNotSupported();
}
if (amount0_ == 0 && amount1_ == 0) {
revert AmountsZero();
}
if (amount0_ > 0) {
token0.safeTransferFrom(
depositor_, address(this), amount0_
);
}
if (amount1_ > 0) {
token1.safeTransferFrom(
depositor_, address(this), amount1_
);
}
emit LogFund(depositor_, amount0_, amount1_);
}
/// @inheritdoc IArrakisLPModule
function withdraw(
address receiver_,
uint256 proportion_
)
public
virtual
onlyMetaVault
nonReentrant
returns (uint256 amount0, uint256 amount1)
{
/// @dev decrease nft position or burn it.
// #region checks.
if (receiver_ == address(0)) revert AddressZero();
if (proportion_ == 0) revert ProportionZero();
if (proportion_ > BASE) revert ProportionGtBASE();
// #endregion checks.
uint256[] memory tokenIds = _tokenIds.values();
uint256 aeroAmountCollected;
IERC20Metadata _token0 = token0;
IERC20Metadata _token1 = token1;
amount0 = FullMath.mulDiv(
_token0.balanceOf(address(this)), proportion_, BASE
);
amount1 = FullMath.mulDiv(
_token1.balanceOf(address(this)), proportion_, BASE
);
// #region get sqrtPriceX96 from oracle price.
(uint160 sqrtPriceX96,,,,,) = IUniswapV3Pool(pool).slot0();
// #endregion get sqrtPriceX96 from oracle price.
ModifyPosition memory modifyPosition;
modifyPosition.proportion = proportion_;
for (uint256 i; i < tokenIds.length;) {
modifyPosition.tokenId = tokenIds[i];
(uint256 amt0, uint256 amt1, uint256 aeroCo) =
_decreaseLiquidity(modifyPosition, sqrtPriceX96);
amount0 += amt0;
amount1 += amt1;
aeroAmountCollected += aeroCo;
unchecked {
i += 1;
}
}
// #region take the manager share.
uint256 _managerFeePIPS = managerFeePIPS;
_aeroManagerBalance += FullMath.mulDiv(
aeroAmountCollected, _managerFeePIPS, PIPS
);
// #endregion take the manager share.
if (amount0 > 0) {
_token0.safeTransfer(receiver_, amount0);
}
if (amount1 > 0) {
_token1.safeTransfer(receiver_, amount1);
}
emit LogWithdraw(receiver_, proportion_, amount0, amount1);
}
/// @inheritdoc IAerodromeStandardModulePrivate
function claimRewards(
address receiver_
) external onlyMetaVaultOwner nonReentrant whenNotPaused {
// #region checks.
if (receiver_ == address(0)) {
revert AddressZero();
}
// #endregion checks.
uint256 length = _tokenIds.length();
uint256 aeroBalance;
address _gauge = gauge;
uint256 balance =
IERC20Metadata(AERO).balanceOf(address(this));
for (uint256 i; i < length;) {
uint256 tokenId = _tokenIds.at(i);
ICLGauge(_gauge).getReward(tokenId);
unchecked {
i += 1;
}
}
aeroBalance +=
IERC20Metadata(AERO).balanceOf(address(this)) - balance;
// #region take the manager share.
_aeroManagerBalance +=
FullMath.mulDiv(aeroBalance, managerFeePIPS, PIPS);
// #endregion take the manager share.
uint256 aeroToClaim = IERC20Metadata(AERO).balanceOf(
address(this)
) - _aeroManagerBalance;
IERC20Metadata(AERO).safeTransfer(receiver_, aeroToClaim);
emit LogClaim(receiver_, aeroToClaim);
}
/// @inheritdoc IAerodromeStandardModulePrivate
function setReceiver(
address newReceiver_
) external whenNotPaused {
address manager = metaVault.manager();
if (IOwnable(manager).owner() != msg.sender) {
revert OnlyManagerOwner();
}
address oldReceiver = aeroReceiver;
if (newReceiver_ == address(0)) {
revert AddressZero();
}
if (oldReceiver == newReceiver_) {
revert SameReceiver();
}
aeroReceiver = newReceiver_;
emit LogSetReceiver(oldReceiver, newReceiver_);
}
/// @inheritdoc IAerodromeStandardModulePrivate
function claimManager() public nonReentrant whenNotPaused {
uint256 length = _tokenIds.length();
address _gauge = gauge;
uint256 aeroBalance =
IERC20Metadata(AERO).balanceOf(address(this));
for (uint256 i; i < length;) {
uint256 tokenId = _tokenIds.at(i);
ICLGauge(_gauge).getReward(tokenId);
unchecked {
i += 1;
}
}
aeroBalance =
IERC20Metadata(AERO).balanceOf(address(this)) - aeroBalance;
// #region take the manager share.
uint256 amountToSend = _aeroManagerBalance
+ FullMath.mulDiv(aeroBalance, managerFeePIPS, PIPS);
_aeroManagerBalance = 0;
// #endregion take the manager share.
address _aeroReceiver = aeroReceiver;
IERC20Metadata(AERO).safeTransfer(_aeroReceiver, amountToSend);
emit LogManagerClaim(_aeroReceiver, amountToSend);
}
/// @inheritdoc IAerodromeStandardModulePrivate
function rebalance(
RebalanceParams calldata params_
) external nonReentrant whenNotPaused onlyManager {
// #region modify postitions.
uint256 length = params_.decreasePositions.length;
uint256 burn0;
uint256 burn1;
// #region get sqrtPriceX96 from oracle price.
(uint160 sqrtPriceX96,,,,,) = IUniswapV3Pool(pool).slot0();
// #endregion get sqrtPriceX96 from oracle price.
if (length > 0) {
uint256 aeroAmountCollected;
uint256 _managerFeePIPS = managerFeePIPS;
for (uint256 i; i < length;) {
if (
!_tokenIds.contains(
params_.decreasePositions[i].tokenId
)
) {
revert TokenIdNotFound();
}
(uint256 amt0, uint256 amt1, uint256 aeroCo) =
_decreaseLiquidity(
params_.decreasePositions[i], sqrtPriceX96
);
burn0 += amt0;
burn1 += amt1;
aeroAmountCollected += aeroCo;
unchecked {
i += 1;
}
}
// #region manager fees.
_aeroManagerBalance += FullMath.mulDiv(
aeroAmountCollected, _managerFeePIPS, PIPS
);
// #endregion manager fees.
// #region minBurns.
if (burn0 < params_.minBurn0) {
revert BurnToken0();
}
if (burn1 < params_.minBurn1) {
revert BurnToken1();
}
// #endregion minBurns.
}
// #endregion modify positions.
// #region swap.
if (params_.swapPayload.amountIn > 0) {
IERC20Metadata _token0 = token0;
IERC20Metadata _token1 = token1;
_checkMinReturn(
params_.swapPayload.zeroForOne,
params_.swapPayload.expectedMinReturn,
params_.swapPayload.amountIn,
_token0.decimals(),
_token1.decimals()
);
uint256 balance;
if (params_.swapPayload.zeroForOne) {
_token0.forceApprove(
params_.swapPayload.router,
params_.swapPayload.amountIn
);
balance = _token1.balanceOf(address(this));
} else {
_token1.forceApprove(
params_.swapPayload.router,
params_.swapPayload.amountIn
);
balance = _token0.balanceOf(address(this));
}
if (
params_.swapPayload.router == address(metaVault)
|| params_.swapPayload.router
== address(nftPositionManager)
|| params_.swapPayload.router == gauge
|| params_.swapPayload.router == AERO
) {
revert WrongRouter();
}
{
params_.swapPayload.router.functionCall(
params_.swapPayload.payload
);
}
if (params_.swapPayload.zeroForOne) {
balance = _token1.balanceOf(address(this)) - balance;
if (params_.swapPayload.expectedMinReturn > balance) {
revert SlippageTooHigh();
}
_token0.forceApprove(params_.swapPayload.router, 0);
} else {
balance = _token0.balanceOf(address(this)) - balance;
if (params_.swapPayload.expectedMinReturn > balance) {
revert SlippageTooHigh();
}
_token1.forceApprove(params_.swapPayload.router, 0);
}
}
// #endregion swap.
uint256 mint0;
uint256 mint1;
// #region increase positions.
(sqrtPriceX96,,,,,) = IUniswapV3Pool(pool).slot0();
length = params_.increasePositions.length;
if (length > 0) {
uint256 aeroAmountCollected;
uint256 _managerFeePIPS = managerFeePIPS;
for (uint256 i; i < length;) {
if (
!_tokenIds.contains(
params_.increasePositions[i].tokenId
)
) {
revert TokenIdNotFound();
}
(uint256 amt0, uint256 amt1, uint256 aeroCo) =
_increaseLiquidity(
params_.increasePositions[i], sqrtPriceX96
);
mint0 += amt0;
mint1 += amt1;
aeroAmountCollected += aeroCo;
unchecked {
i += 1;
}
}
// #region manager fees.
_aeroManagerBalance += FullMath.mulDiv(
aeroAmountCollected, _managerFeePIPS, PIPS
);
// #endregion manager fees.
}
// #endregion increase positions.
// #region mint.
length = params_.mintParams.length;
if (length > 0) {
address _token0 = address(token0);
address _token1 = address(token1);
for (uint256 i; i < length;) {
(uint256 amount0, uint256 amount1) =
_mint(params_.mintParams[i], _token0, _token1);
mint0 += amount0;
mint1 += amount1;
unchecked {
i += 1;
}
}
if (mint0 < params_.minDeposit0) {
revert MintToken0();
}
if (mint1 < params_.minDeposit1) {
revert MintToken1();
}
}
// #endregion mint.
emit LogRebalance(burn0, burn1, mint0, mint1);
}
/// @inheritdoc IArrakisLPModule
function withdrawManagerBalance()
public
nonReentrant
whenNotPaused
returns (uint256 amount0, uint256 amount1)
{}
/// @inheritdoc IArrakisLPModule
function setManagerFeePIPS(
uint256 newFeePIPS_
) external onlyManager whenNotPaused {
uint256 _managerFeePIPS = managerFeePIPS;
if (_managerFeePIPS == newFeePIPS_) revert SameManagerFee();
if (newFeePIPS_ > PIPS) revert NewFeesGtPIPS(newFeePIPS_);
claimManager();
managerFeePIPS = newFeePIPS_;
emit LogSetManagerFeePIPS(_managerFeePIPS, newFeePIPS_);
}
// #region view functions.
/// @inheritdoc IArrakisLPModule
function guardian() external view returns (address) {
return IGuardian(_guardian).pauser();
}
/// @inheritdoc IAerodromeStandardModulePrivate
function tokenIds() external view returns (uint256[] memory) {
return _tokenIds.values();
}
/// @inheritdoc IArrakisLPModule
function getInits()
external
view
returns (uint256 init0, uint256 init1)
{}
/// @inheritdoc IArrakisLPModule
function totalUnderlying()
external
view
returns (uint256 amount0, uint256 amount1)
{
uint256 length = _tokenIds.length();
(uint160 sqrtPriceX96,,,,,) = IUniswapV3Pool(pool).slot0();
for (uint256 i; i < length;) {
(uint256 amt0, uint256 amt1) =
_principal(_tokenIds.at(i), sqrtPriceX96);
amount0 += amt0;
amount1 += amt1;
unchecked {
i += 1;
}
}
// #region left over.
amount0 += token0.balanceOf(address(this));
amount1 += token1.balanceOf(address(this));
// #endregion left over.
}
/// @inheritdoc IArrakisLPModule
function totalUnderlyingAtPrice(
uint160 priceX96_
) external view returns (uint256 amount0, uint256 amount1) {
uint256 length = _tokenIds.length();
for (uint256 i; i < length;) {
(uint256 amt0, uint256 amt1) =
_principal(_tokenIds.at(i), priceX96_);
amount0 += amt0;
amount1 += amt1;
unchecked {
i += 1;
}
}
// #region left over.
amount0 += token0.balanceOf(address(this));
amount1 += token1.balanceOf(address(this));
// #endregion left over.
}
/// @inheritdoc IArrakisLPModule
function validateRebalance(
IOracleWrapper oracle_,
uint24 maxDeviation_
) external view {
IERC20Metadata _token0 = token0;
IERC20Metadata _token1 = token1;
uint8 token0Decimals = _token0.decimals();
uint8 token1Decimals = _token1.decimals();
uint256 oraclePrice = oracle_.getPrice0();
(uint160 sqrtPriceX96,,,,,) = IUniswapV3Pool(pool).slot0();
uint256 poolPrice;
if (sqrtPriceX96 <= type(uint128).max) {
poolPrice = FullMath.mulDiv(
uint256(sqrtPriceX96) * uint256(sqrtPriceX96),
10 ** token0Decimals,
1 << 192
);
} else {
poolPrice = FullMath.mulDiv(
FullMath.mulDiv(
uint256(sqrtPriceX96),
uint256(sqrtPriceX96),
1 << 64
),
10 ** token0Decimals,
1 << 128
);
}
uint256 deviation = FullMath.mulDiv(
FullMath.mulDiv(
poolPrice > oraclePrice
? poolPrice - oraclePrice
: oraclePrice - poolPrice,
10 ** token1Decimals,
poolPrice
),
PIPS,
10 ** token1Decimals
);
if (deviation > maxDeviation_) revert OverMaxDeviation();
}
/// @inheritdoc IArrakisLPModule
function managerBalance0()
external
view
returns (uint256 managerFee0)
{}
/// @inheritdoc IArrakisLPModule
function managerBalance1()
external
view
returns (uint256 managerFee1)
{}
/// @inheritdoc IAerodromeStandardModulePrivate
function aeroManagerBalance() external view returns (uint256) {
uint256 aeroBalance;
uint256 length = _tokenIds.length();
address _gauge = gauge;
for (uint256 i; i < length;) {
uint256 tokenId = _tokenIds.at(i);
aeroBalance += ICLGauge(_gauge).rewards(tokenId);
aeroBalance +=
ICLGauge(_gauge).earned(address(this), tokenId);
unchecked {
i += 1;
}
}
return _aeroManagerBalance
+ FullMath.mulDiv(aeroBalance, managerFeePIPS, PIPS);
}
// #endregion view functions.
// #region internal functions.
function _decreaseLiquidity(
ModifyPosition memory modifyPosition_,
uint160 sqrtPriceX96_
)
internal
returns (
uint256 amount0ToSend,
uint256 amount1ToSend,
uint256 aeroAmountCollected
)
{
// #region unstake position.
address _gauge;
uint128 liquidity;
{
uint256 aeroAmountCo;
(aeroAmountCo, _gauge, liquidity) =
_unstake(modifyPosition_.tokenId);
aeroAmountCollected += aeroAmountCo;
}
// #endregion unstake position.
{
liquidity = SafeCast.toUint128(
FullMath.mulDiv(
liquidity, modifyPosition_.proportion, BASE
)
);
INonfungiblePositionManager.DecreaseLiquidityParams memory
params = INonfungiblePositionManager
.DecreaseLiquidityParams({
tokenId: modifyPosition_.tokenId,
liquidity: liquidity,
amount0Min: 0,
amount1Min: 0,
deadline: type(uint256).max
});
nftPositionManager.decreaseLiquidity(params);
}
(amount0ToSend, amount1ToSend) = nftPositionManager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: modifyPosition_.tokenId,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
if (modifyPosition_.proportion == BASE) {
nftPositionManager.burn(modifyPosition_.tokenId);
_tokenIds.remove(modifyPosition_.tokenId);
} else {
nftPositionManager.approve(
_gauge, modifyPosition_.tokenId
);
ICLGauge(_gauge).deposit(modifyPosition_.tokenId);
}
}
function _increaseLiquidity(
ModifyPosition memory modifyPosition_,
uint160 sqrtPriceX96_
)
internal
returns (
uint256 amount0Sent,
uint256 amount1Sent,
uint256 aeroAmountCollected
)
{
// #region principals.
uint256 amt0;
uint256 amt1;
{
(amt0, amt1) =
_principal(modifyPosition_.tokenId, sqrtPriceX96_);
}
// #endregion principals.
// #region unstake position.
address _gauge;
{
uint256 aeroAmountCo;
(aeroAmountCo, _gauge,) =
_unstake(modifyPosition_.tokenId);
aeroAmountCollected += aeroAmountCo;
}
// #endregion unstake position.
amt0 = SafeCast.toUint128(
FullMath.mulDiv(amt0, modifyPosition_.proportion, BASE)
);
amt1 = SafeCast.toUint128(
FullMath.mulDiv(amt1, modifyPosition_.proportion, BASE)
);
{
INonfungiblePositionManager.IncreaseLiquidityParams memory
params = INonfungiblePositionManager
.IncreaseLiquidityParams({
tokenId: modifyPosition_.tokenId,
amount0Desired: amt0,
amount1Desired: amt1,
amount0Min: 0,
amount1Min: 0,
deadline: type(uint256).max
});
// #region approves.
IERC20Metadata _token0 = token0;
IERC20Metadata _token1 = token1;
if (params.amount0Desired > 0) {
_token0.forceApprove(
address(nftPositionManager), params.amount0Desired
);
}
if (params.amount1Desired > 0) {
_token1.forceApprove(
address(nftPositionManager), params.amount1Desired
);
}
// #endregion approves.
(, amount0Sent, amount1Sent) =
nftPositionManager.increaseLiquidity(params);
if (params.amount0Desired > 0) {
_token0.forceApprove(address(nftPositionManager), 0);
}
if (params.amount1Desired > 0) {
_token1.forceApprove(address(nftPositionManager), 0);
}
}
nftPositionManager.approve(_gauge, modifyPosition_.tokenId);
ICLGauge(_gauge).deposit(modifyPosition_.tokenId);
}
function _unstake(
uint256 tokenId_
)
internal
returns (
uint256 aeroAmountCollected,
address _gauge,
uint128 liquidity
)
{
// #region get rewards.
{
(,, liquidity) = _getPosition(tokenId_);
_gauge = gauge;
}
uint256 aeroBalance =
IERC20Metadata(AERO).balanceOf(address(this));
ICLGauge(_gauge).withdraw(tokenId_);
aeroAmountCollected += (
IERC20Metadata(AERO).balanceOf(address(this))
- aeroBalance
);
// #endregion get rewards.
}
function _mint(
INonfungiblePositionManager.MintParams calldata params_,
address token0_,
address token1_
) internal returns (uint256 amount0, uint256 amount1) {
uint256 tokenId;
if (params_.token0 != token0_) {
revert Token0Mismatch();
}
if (params_.token1 != token1_) {
revert Token1Mismatch();
}
int24 tickSpacing = IUniswapV3Pool(pool).tickSpacing();
if (params_.tickSpacing != tickSpacing) {
revert TickSpacingMismatch();
}
// #region approves.
if (params_.amount0Desired > 0) {
IERC20Metadata(token0_).forceApprove(
address(nftPositionManager), params_.amount0Desired
);
}
if (params_.amount1Desired > 0) {
IERC20Metadata(token1_).forceApprove(
address(nftPositionManager), params_.amount1Desired
);
}
// #endregion approves.
(tokenId,, amount0, amount1) =
nftPositionManager.mint(params_);
if (params_.amount0Desired > 0) {
IERC20Metadata(token0_).forceApprove(
address(nftPositionManager), 0
);
}
if (params_.amount1Desired > 0) {
IERC20Metadata(token1_).forceApprove(
address(nftPositionManager), 0
);
}
_tokenIds.add(tokenId);
// #region stake.
address _gauge = gauge;
nftPositionManager.approve(_gauge, tokenId);
ICLGauge(_gauge).deposit(tokenId);
// #endregion stake.
}
function _checkMinReturn(
bool zeroForOne_,
uint256 expectedMinReturn_,
uint256 amountIn_,
uint8 decimals0_,
uint8 decimals1_
) internal view {
if (zeroForOne_) {
if (
FullMath.mulDiv(
expectedMinReturn_, 10 ** decimals0_, amountIn_
)
< FullMath.mulDiv(
oracle.getPrice0(), PIPS - maxSlippage, PIPS
)
) revert ExpectedMinReturnTooLow();
} else {
if (
FullMath.mulDiv(
expectedMinReturn_, 10 ** decimals1_, amountIn_
)
< FullMath.mulDiv(
oracle.getPrice1(), PIPS - maxSlippage, PIPS
)
) revert ExpectedMinReturnTooLow();
}
}
function _principal(
uint256 tokenId_,
uint160 sqrtRatioX96_
) internal view returns (uint256 amount0, uint256 amount1) {
(int24 tickLower, int24 tickUpper, uint128 liquidity) =
_getPosition(tokenId_);
(amount0, amount1) = LiquidityAmounts.getAmountsForLiquidity(
sqrtRatioX96_,
TickMath.getSqrtRatioAtTick(tickLower),
TickMath.getSqrtRatioAtTick(tickUpper),
liquidity
);
}
/// @dev trick to workaround stack too deep.
function _getPosition(
uint256 tokenId_
)
internal
view
returns (int24 tickLower, int24 tickUpper, uint128 liquidity)
{
bytes memory payload = abi.encodeWithSelector(
INonfungiblePositionManager.positions.selector, tokenId_
);
bytes memory result =
address(nftPositionManager).functionStaticCall(payload);
(,,,,, tickLower, tickUpper, liquidity) = abi.decode(
result,
(
uint96,
address,
address,
address,
int24,
int24,
int24,
uint128
)
);
}
// #endregion internal functions.
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IERC20Metadata} from
"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IArrakisMetaVault} from "./IArrakisMetaVault.sol";
import {IOracleWrapper} from "./IOracleWrapper.sol";
/// @title Liquidity providing module interface.
/// @author Arrakis Finance
/// @notice Module interfaces, modules are implementing differents strategies that an
/// arrakis module can use.
interface IArrakisLPModule {
// #region errors.
/// @dev triggered when an address that should not
/// be zero is equal to address zero.
error AddressZero();
/// @dev triggered when the caller is different than
/// the metaVault that own this module.
error OnlyMetaVault(address caller, address metaVault);
/// @dev triggered when the caller is different than
/// the manager defined by the metaVault.
error OnlyManager(address caller, address manager);
/// @dev triggered if proportion of minting or burning is
/// zero.
error ProportionZero();
/// @dev triggered if during withdraw more than 100% of the
/// position.
error ProportionGtBASE();
/// @dev triggered when manager want to set his more
/// earned by the position than 100% of fees earned.
error NewFeesGtPIPS(uint256 newFees);
/// @dev triggered when manager is setting the same fees
/// that already active.
error SameManagerFee();
/// @dev triggered when inits values are zeros.
error InitsAreZeros();
/// @dev triggered when pause/unpaused function is
/// called by someone else than guardian.
error OnlyGuardian();
// #endregion errors.
// #region events.
/// @notice Event describing a withdrawal of participation by an user inside this module.
/// @dev withdraw action can be indexed by receiver.
/// @param receiver address that will receive the tokens withdrawn.
/// @param proportion percentage of the current position that user want to withdraw.
/// @param amount0 amount of token0 send to "receiver" due to withdraw action.
/// @param amount1 amount of token1 send to "receiver" due to withdraw action.
event LogWithdraw(
address indexed receiver,
uint256 proportion,
uint256 amount0,
uint256 amount1
);
/// @notice Event describing a manager fee withdrawal.
/// @param manager address of the manager that will fees earned due to his fund management.
/// @param amount0 amount of token0 that manager has earned and will be transfered.
/// @param amount1 amount of token1 that manager has earned and will be transfered.
event LogWithdrawManagerBalance(
address manager, uint256 amount0, uint256 amount1
);
/// @notice Event describing manager set his fees.
/// @param oldFee fees share that have been taken by manager.
/// @param newFee fees share that have been taken by manager.
event LogSetManagerFeePIPS(uint256 oldFee, uint256 newFee);
// #endregion events.
/// @notice function used to pause the module.
/// @dev only callable by guardian
function pause() external;
/// @notice function used to unpause the module.
/// @dev only callable by guardian
function unpause() external;
/// @notice function used to initialize the module
/// when a module switch happen
/// @param data_ bytes that contain information to initialize
/// the position.
function initializePosition(bytes calldata data_) external;
/// @notice function used by metaVault to withdraw tokens from the strategy.
/// @param receiver_ address that will receive tokens.
/// @param proportion_ the proportion of the total position that need to be withdrawn.
/// @return amount0 amount of token0 withdrawn.
/// @return amount1 amount of token1 withdrawn.
function withdraw(
address receiver_,
uint256 proportion_
) external returns (uint256 amount0, uint256 amount1);
/// @notice function used by metaVault or manager to get manager fees.
/// @return amount0 amount of token0 sent to manager.
/// @return amount1 amount of token1 sent to manager.
function withdrawManagerBalance()
external
returns (uint256 amount0, uint256 amount1);
/// @notice function used to set manager fees.
/// @param newFeePIPS_ new fee that will be applied.
function setManagerFeePIPS(uint256 newFeePIPS_) external;
// #region view functions.
/// @notice function used to get metaVault as IArrakisMetaVault.
/// @return metaVault that implement IArrakisMetaVault.
function metaVault() external view returns (IArrakisMetaVault);
/// @notice function used to get the address that can pause the module.
/// @return guardian address of the pauser.
function guardian() external view returns (address);
/// @notice function used to get manager token0 balance.
/// @dev amount of fees in token0 that manager have not taken yet.
/// @return managerBalance0 amount of token0 that manager earned.
function managerBalance0() external view returns (uint256);
/// @notice function used to get manager token1 balance.
/// @dev amount of fees in token1 that manager have not taken yet.
/// @return managerBalance1 amount of token1 that manager earned.
function managerBalance1() external view returns (uint256);
/// @notice function used to get manager fees.
/// @return managerFeePIPS amount of token1 that manager earned.
function managerFeePIPS() external view returns (uint256);
/// @notice function used to get token0 as IERC20Metadata.
/// @return token0 as IERC20Metadata.
function token0() external view returns (IERC20Metadata);
/// @notice function used to get token1 as IERC20Metadata.
/// @return token1 as IERC20Metadata.
function token1() external view returns (IERC20Metadata);
/// @notice function used to get the initial amounts needed to open a position.
/// @return init0 the amount of token0 needed to open a position.
/// @return init1 the amount of token1 needed to open a position.
function getInits()
external
view
returns (uint256 init0, uint256 init1);
/// @notice function used to get the amount of token0 and token1 sitting
/// on the position.
/// @return amount0 the amount of token0 sitting on the position.
/// @return amount1 the amount of token1 sitting on the position.
function totalUnderlying()
external
view
returns (uint256 amount0, uint256 amount1);
/// @notice function used to get the amounts of token0 and token1 sitting
/// on the position for a specific price.
/// @param priceX96_ price at which we want to simulate our tokens composition
/// @return amount0 the amount of token0 sitting on the position for priceX96.
/// @return amount1 the amount of token1 sitting on the position for priceX96.
function totalUnderlyingAtPrice(uint160 priceX96_)
external
view
returns (uint256 amount0, uint256 amount1);
/// @notice function used to validate if module state is not manipulated
/// before rebalance.
/// @param oracle_ oracle that will used to check internal state.
/// @param maxDeviation_ maximum deviation allowed.
function validateRebalance(
IOracleWrapper oracle_,
uint24 maxDeviation_
) external view;
// #endregion view function.
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/// @notice expose a deposit function for that can
/// deposit any share of token0 and token1.
/// @dev this deposit feature will be used by
/// private actor.
interface IArrakisLPModulePrivate {
// #region errors.
error DepositZero();
// #endregion errors.
// #region events.
/// @notice event emitted when owner of private fund the private vault.
/// @param depositor address that are sending the tokens, the owner.
/// @param amount0 amount of token0 sent by depositor.
/// @param amount1 amount of token1 sent by depositor.
event LogFund(
address depositor, uint256 amount0, uint256 amount1
);
// #endregion events.
/// @notice deposit function for private vault.
/// @param depositor_ address that will provide the tokens.
/// @param amount0_ amount of token0 that depositor want to send to module.
/// @param amount1_ amount of token1 that depositor want to send to module.
function fund(
address depositor_,
uint256 amount0_,
uint256 amount1_
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IArrakisLPModule} from "./IArrakisLPModule.sol";
/// @title IArrakisMetaVault
/// @notice IArrakisMetaVault is a vault that is able to invest dynamically deposited
/// tokens into protocols through his module.
interface IArrakisMetaVault {
// #region errors.
/// @dev triggered when an address that should not
/// be zero is equal to address zero.
error AddressZero(string property);
/// @dev triggered when the caller is different than
/// the manager.
error OnlyManager(address caller, address manager);
/// @dev triggered when a low level call failed during
/// execution.
error CallFailed();
/// @dev triggered when manager try to set the active
/// module as active.
error SameModule();
/// @dev triggered when owner of the vault try to set the
/// manager with the current manager.
error SameManager();
/// @dev triggered when all tokens withdrawal has been done
/// during a switch of module.
error ModuleNotEmpty(uint256 amount0, uint256 amount1);
/// @dev triggered when owner try to whitelist a module
/// that has been already whitelisted.
error AlreadyWhitelisted(address module);
/// @dev triggered when owner try to blacklist a module
/// that has not been whitelisted.
error NotWhitelistedModule(address module);
/// @dev triggered when owner try to blacklist the active module.
error ActiveModule();
/// @dev triggered during vault creation if token0 address is greater than
/// token1 address.
error Token0GtToken1();
/// @dev triggered during vault creation if token0 address is equal to
/// token1 address.
error Token0EqToken1();
/// @dev triggered when whitelisting action is occuring and module's beacon
/// is not whitelisted on module registry.
error NotWhitelistedBeacon();
/// @dev triggered when guardian of the whitelisting module is different than
/// the guardian of the registry.
error NotSameGuardian();
/// @dev triggered when a function logic is not implemented.
error NotImplemented();
/// @dev triggered when two arrays suppposed to have the same length, have different length.
error ArrayNotSameLength();
/// @dev triggered when function is called by someone else than the owner.
error OnlyOwner();
/// @dev triggered when setModule action try to remove funds.
error WithdrawNotAllowed();
/// @dev triggered when setModule function end without
/// initiliazePosition call.
error PositionNotInitialized();
/// @dev triggered when the first external call of setModule function
/// isn't InitializePosition function.
error NotPositionInitializationCall();
// #endregion errors.
// #region events.
/// @notice Event describing a manager fee withdrawal.
/// @param amount0 amount of token0 that manager has earned and will be transfered.
/// @param amount1 amount of token1 that manager has earned and will be transfered.
event LogWithdrawManagerBalance(uint256 amount0, uint256 amount1);
/// @notice Event describing owner setting the manager.
/// @param manager address of manager that will manage the portfolio.
event LogSetManager(address manager);
/// @notice Event describing manager setting the module.
/// @param module address of the new active module.
/// @param payloads data payloads for initializing positions on the new module.
event LogSetModule(address module, bytes[] payloads);
/// @notice Event describing default module that the vault will be initialized with.
/// @param module address of the default module.
event LogSetFirstModule(address module);
/// @notice Event describing list of modules that has been whitelisted by owner.
/// @param modules list of addresses corresponding to new modules now available
/// to be activated by manager.
event LogWhiteListedModules(address[] modules);
/// @notice Event describing whitelisted of the first module during vault creation.
/// @param module default activation.
event LogWhitelistedModule(address module);
/// @notice Event describing blacklisting action of modules by owner.
/// @param modules list of addresses corresponding to old modules that has been
/// blacklisted.
event LogBlackListedModules(address[] modules);
// #endregion events.
/// @notice function used to initialize default module.
/// @param module_ address of the default module.
function initialize(address module_) external;
/// @notice function used to set module
/// @param module_ address of the new module
/// @param payloads_ datas to initialize/rebalance on the new module
function setModule(
address module_,
bytes[] calldata payloads_
) external;
/// @notice function used to whitelist modules that can used by manager.
/// @param beacons_ array of beacons addresses to use for modules creation.
/// @param data_ array of payload to use for modules creation.
function whitelistModules(
address[] calldata beacons_,
bytes[] calldata data_
) external;
/// @notice function used to blacklist modules that can used by manager.
/// @param modules_ array of module addresses to be blacklisted.
function blacklistModules(address[] calldata modules_) external;
// #region view functions.
/// @notice function used to get the list of modules whitelisted.
/// @return modules whitelisted modules addresses.
function whitelistedModules()
external
view
returns (address[] memory modules);
/// @notice function used to get the amount of token0 and token1 sitting
/// on the position.
/// @return amount0 the amount of token0 sitting on the position.
/// @return amount1 the amount of token1 sitting on the position.
function totalUnderlying()
external
view
returns (uint256 amount0, uint256 amount1);
/// @notice function used to get the amounts of token0 and token1 sitting
/// on the position for a specific price.
/// @param priceX96 price at which we want to simulate our tokens composition
/// @return amount0 the amount of token0 sitting on the position for priceX96.
/// @return amount1 the amount of token1 sitting on the position for priceX96.
function totalUnderlyingAtPrice(uint160 priceX96)
external
view
returns (uint256 amount0, uint256 amount1);
/// @notice function used to get the initial amounts needed to open a position.
/// @return init0 the amount of token0 needed to open a position.
/// @return init1 the amount of token1 needed to open a position.
function getInits()
external
view
returns (uint256 init0, uint256 init1);
/// @notice function used to get the address of token0.
function token0() external view returns (address);
/// @notice function used to get the address of token1.
function token1() external view returns (address);
/// @notice function used to get manager address.
function manager() external view returns (address);
/// @notice function used to get module used to
/// open/close/manager a position.
function module() external view returns (IArrakisLPModule);
/// @notice function used to get module registry.
/// @return registry address of module registry.
function moduleRegistry()
external
view
returns (address registry);
// #endregion view functions.
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IUniswapV3Factory} from "./IUniswapV3Factory.sol";
import {INonfungiblePositionManager} from "./INonfungiblePositionManager.sol";
import {IVoter} from "./IVoter.sol";
import {IOracleWrapper} from "./IOracleWrapper.sol";
import {RebalanceParams} from "../structs/SUniswapV3.sol";
/// @title Aerodrome Standard Private Module.
/// @author Arrakis Finance
/// @notice Aerodrome Module interface, modules able to interact with aerodrome dex.
interface IAerodromeStandardModulePrivate {
// #region errors.
/// @dev triggered when the max slippage variable is set to greater than 10%.
error MaxSlippageGtTenPercent();
/// @dev triggered when the caller is different than the meta vault owner.
error OnlyMetaVaultOwner();
/// @dev triggered when token pair contain native coin.
error NativeCoinNotSupported();
/// @dev triggered when burn of token0 is smaller than expected.
error BurnToken0();
/// @dev triggered when burn of token1 is smaller than expected.
error BurnToken1();
/// @dev triggered when mint of token0 is smaller than expected.
error MintToken0();
/// @dev triggered when mint of token1 is smaller than expected.
error MintToken1();
/// @dev triggered when tokenId of position is unknown from the module.
error TokenIdNotFound();
/// @dev triggered when token0 of mintParams is different than module token0.
error Token0Mismatch();
/// @dev triggered when token1 of mintParams is different than module token1.
error Token1Mismatch();
/// @dev triggered when tick spacing of mintParams is different than the pool module.
error TickSpacingMismatch();
/// @dev triggered when min return of rebalance swap is too low.
error ExpectedMinReturnTooLow();
/// @dev triggered when swap router of the rebalance payload is unauthorized address.
error WrongRouter();
/// @dev triggered when amount received from rebalance swap is too low.
error SlippageTooHigh();
/// @dev triggered when deviation of pool price from oracle price is
/// greater than max allowed value.
error OverMaxDeviation();
/// @dev triggered when new aero receiver is equal to old aero receiver.
error SameReceiver();
/// @dev triggered when pool has not been created on factory.
error PoolNotFound();
/// @dev triggered when funded amounts are equals to zero.
error AmountsZero();
/// @dev triggered when caller is not the owner of the manager.
error OnlyManagerOwner();
/// @dev triggered when aero token is one of the token of the module token pair.
error AEROTokenNotSupported();
/// @dev triggered when gauge returned by voter is not alive.
error GaugeKilled();
// #endregion errors.
// #region events.
/// @notice Event describing an approval of left overs to an address.
/// @param spender the address that will get the allowance.
/// @param amount0 the amount of token0 allowed to spender.
/// @param amount1 the amount of token1 allowed to spender.
event LogApproval(
address indexed spender,
uint256 amount0,
uint256 amount1
);
/// @notice Event describing an rebalance results on underlying.
/// @param burn0 the amount of token0 burned during rebalance.
/// @param burn1 the amount of token1 burned during rebalance.
/// @param mint0 the amount of token0 minted during rebalance.
/// @param mint1 the amount of token1 minted during rebalance.
event LogRebalance(
uint256 burn0,
uint256 burn1,
uint256 mint0,
uint256 mint1
);
/// @notice Event describing an claim by user of aero token.
/// @param receiver the receiver of aero token.
/// @param aeroAmount the amount of aero token claimed.
event LogClaim(
address indexed receiver,
uint256 aeroAmount
);
/// @notice Event describing an claim by manager of aero token.
/// @param receiver the receiver of aero token.
/// @param aeroAmount the amount of aero token claimed.
event LogManagerClaim(
address indexed receiver,
uint256 aeroAmount
);
/// @notice Event describing the update of receiver of manager aero reward.
/// @param oldReceiver previous receiver of aero token.
/// @param newReceiver new receiver of aero token.
event LogSetReceiver(address oldReceiver, address newReceiver);
// #endregion events.
/// @notice initialize function to delegate call onced the beacon proxy is deployed,
/// for initializing the aerodrome module.
/// @param oracle_ oracle that will be the price reference.
/// @param maxSlippage_ maximum slippage allowed during swap, mint and burn.
/// @param aeroReceiver_ recevier of aero token belonging to manager.
/// @param tickSpacing_ tickSpacing of the aero pool to interact with.
/// @param metaVault_ address of the meta vault
function initialize(
IOracleWrapper oracle_,
uint24 maxSlippage_,
address aeroReceiver_,
int24 tickSpacing_,
address metaVault_
) external;
/// @notice function used to rebalance the inventory of the module.
/// @param params_ params including decrease positions, swap, increase positions and mint datas.
function rebalance(RebalanceParams calldata params_) external;
/// @notice function used by user to claim the aero rewards.
/// @param receiver_ address that will receive the aero rewards.
function claimRewards(address receiver_) external;
/// @notice function used by executor to claim the manager aero rewards.
function claimManager() external;
/// @notice function used to approve a spender to use the left over of the module.
/// @param spender_ address that will be allowed to use left over.
/// @param amount0_ amount of token0 allowed to be used by spender.
/// @param amount1_ amount of token1 allowed to be used by spender.
function approve(
address spender_,
uint256 amount0_,
uint256 amount1_
) external;
/// @notice function used to set the receiver of aero rewards.
/// @param newReceiver_ new address that will receive the aero token.
function setReceiver(
address newReceiver_
) external;
// #region view functions.
/// @notice function used to get the NonFungiblePositionManager of aerodrome.
function nftPositionManager() external view returns (INonfungiblePositionManager);
/// @notice function used to get the factory of aerodrome.
function factory() external view returns (IUniswapV3Factory);
/// @notice function used to get the voter of aerodrome.
function voter() external view returns (IVoter);
/// @notice function used to get the list of tokenIds of non fungible position.
function tokenIds() external view returns (uint256[] memory);
/// @notice function used to get the maximum slippage.
function maxSlippage() external view returns (uint24);
/// @notice function used to get aero token receiver.
function aeroReceiver() external view returns (address);
/// @notice function used to get aero pool the module is interacting with.
function pool() external view returns (address);
/// @notice function used to get aero gauge associated to pool the module is interacting with.
function gauge() external view returns (address);
/// @notice function used to get aero balance due to manager.
function aeroManagerBalance() external view returns (uint256);
/// @notice function used to get the oracle that
/// will be used to proctect rebalances.
function oracle() external view returns (IOracleWrapper);
// #endregion view functions.
// #region constant.
/// @notice function used to get aero token address.
function AERO() external view returns (address);
// #endregion constant.
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IArrakisLPModuleID {
/// @notice function used to get module id.
function id() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUniswapV3Factory {
function getPool(
address tokenA,
address tokenB,
int24 tickSpacing
) external view returns (address pool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface INonfungiblePositionManager {
struct MintParams {
address token0;
address token1;
int24 tickSpacing;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
uint160 sqrtPriceX96;
}
function mint(
MintParams calldata params
)
external
payable
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
struct IncreaseLiquidityParams {
uint256 tokenId;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function increaseLiquidity(
IncreaseLiquidityParams calldata params
)
external
payable
returns (uint128 liquidity, uint256 amount0, uint256 amount1);
struct DecreaseLiquidityParams {
uint256 tokenId;
uint128 liquidity;
uint256 amount0Min;
uint256 amount1Min;
uint256 deadline;
}
function decreaseLiquidity(
DecreaseLiquidityParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
// NOTE : remove collect part if not used.
// #region collect.
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function collect(
CollectParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
// #endregion collect.
function burn(
uint256 tokenId
) external payable;
function positions(uint256 tokenId)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
int24 tickSpacing,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function approve(address to, uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IVoter {
function killGauge(address _gauge) external;
function gauges(address pool) external view returns (address);
function isAlive(address gauge) external view returns (bool);
function emergencyCouncil() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {INonfungiblePositionManager} from "./INonfungiblePositionManager.sol";
import {IVoter} from "./IVoter.sol";
interface ICLGauge {
event NotifyReward(address indexed from, uint256 amount);
event Deposit(address indexed user, uint256 indexed tokenId, uint128 indexed liquidityToStake);
event Withdraw(address indexed user, uint256 indexed tokenId, uint128 indexed liquidityToStake);
event ClaimFees(address indexed from, uint256 claimed0, uint256 claimed1);
event ClaimRewards(address indexed from, uint256 amount);
function nft() external view returns (INonfungiblePositionManager);
function voter() external view returns (IVoter);
function feesVotingReward() external view returns (address);
function periodFinish() external view returns (uint256);
function rewardRate() external view returns (uint256);
function rewards(uint256 tokenId) external view returns (uint256);
function lastUpdateTime(uint256 tokenId) external view returns (uint256);
function rewardRateByEpoch(uint256) external view returns (uint256);
function fees0() external view returns (uint256);
function fees1() external view returns (uint256);
function WETH9() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function tickSpacing() external view returns (int24);
function left() external view returns (uint256 _left);
function rewardToken() external view returns (address);
function isPool() external view returns (bool);
function supportsPayable() external view returns (bool);
function rewardGrowthInside(uint256 tokenId) external view returns (uint256);
function initialize(
address _pool,
address _feesVotingReward,
address _rewardToken,
address _voter,
address _nft,
address _token0,
address _token1,
int24 _tickSpacing,
bool _isPool
) external;
function earned(address account, uint256 tokenId) external view returns (uint256);
function getReward(address account) external;
function getReward(uint256 tokenId) external;
function notifyRewardAmount(uint256 amount) external;
function notifyRewardWithoutClaim(uint256 amount) external;
function deposit(uint256 tokenId) external;
function withdraw(uint256 tokenId) external;
function stakedValues(address depositor) external view returns (uint256[] memory);
function stakedByIndex(address depositor, uint256 index) external view returns (uint256);
function stakedContains(address depositor, uint256 tokenId) external view returns (bool);
function stakedLength(address depositor) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IUniswapV3Pool {
function swap(
address recipient,
bool zeroForOne,
int256 amountSpecified,
uint160 sqrtPriceLimitX96,
bytes calldata data
) external returns (int256 amount0, int256 amount1);
function mint(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount,
bytes calldata data
) external returns (uint256 amount0, uint256 amount1);
function burn(
int24 tickLower,
int24 tickUpper,
uint128 amount
) external returns (uint256 amount0, uint256 amount1);
function collect(
address recipient,
int24 tickLower,
int24 tickUpper,
uint128 amount0Requested,
uint128 amount1Requested
) external returns (uint128 amount0, uint128 amount1);
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
bool unlocked
);
function positions(bytes32 key)
external
view
returns (
uint128 _liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function ticks(int24 tick)
external
view
returns (
uint128 liquidityGross,
int128 liquidityNet,
int128 stakedLiquidityNet,
uint256 feeGrowthOutside0X128,
uint256 feeGrowthOutside1X128,
uint256 rewardGrowthOutsideX128,
int56 tickCumulativeOutside,
uint160 secondsPerLiquidityOutsideX128,
uint32 secondsOutside,
bool initialized
);
function feeGrowthGlobal0X128() external view returns (uint256);
function feeGrowthGlobal1X128() external view returns (uint256);
function tickSpacing() external view returns (int24);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IOracleWrapper {
// #region errors.
error AddressZero();
error DecimalsToken0Zero();
error DecimalsToken1Zero();
// #endregion errors.
/// @notice function used to get price0.
/// @return price0 price of token0/token1.
function getPrice0() external view returns (uint256 price0);
/// @notice function used to get price1.
/// @return price1 price of token1/token0.
function getPrice1() external view returns (uint256 price1);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IOwnable {
/// @notice function used to get the owner of this contract.
function owner() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface IGuardian {
// #region errors.
error AddressZero();
error SamePauser();
// #endregion errors.
// #region events.
/// @notice event emitted when the pauser is set by the owner of the Guardian.
/// @param oldPauser address of the previous pauser.
/// @param newPauser address of the current pauser.
event LogSetPauser(address oldPauser, address newPauser);
// #endregion events.
/// @notice function to get the address of the pauser of arrakis
/// protocol.
/// @return pauser address that can pause the arrakis protocol.
function pauser() external view returns (address);
/// @notice function to set the pauser of Arrakis protocol.
function setPauser(address newPauser_) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
uint256 constant MINIMUM_LIQUIDITY = 10 ** 3;
uint256 constant BASE = 1e18;
uint24 constant PIPS = 1_000_000;
uint24 constant TEN_PERCENT = 100_000;
uint256 constant WEEK = 604_800;
address constant NATIVE_COIN =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint8 constant NATIVE_COIN_DECIMALS = 18;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {IUniswapV3Pool} from "../interfaces/IUniswapV3Pool.sol";
import {INonfungiblePositionManager} from
"../interfaces/INonfungiblePositionManager.sol";
struct Range {
int24 lowerTick;
int24 upperTick;
uint24 feeTier;
}
struct PositionUnderlying {
address nftPositionManager;
address factory;
uint256 tokenId;
}
struct UnderlyingPayload {
uint256[] tokenIds;
address nftPositionManager;
address factory;
uint256 leftOver0;
uint256 leftOver1;
address module;
}
struct GetFeesPayload {
uint256 feeGrowthInside0Last;
uint256 feeGrowthInside1Last;
IUniswapV3Pool pool;
uint128 liquidity;
int24 tick;
int24 lowerTick;
int24 upperTick;
}
struct ComputeFeesPayload {
uint256 feeGrowthInsideLast;
uint256 feeGrowthOutsideLower;
uint256 feeGrowthOutsideUpper;
uint256 feeGrowthGlobal;
uint128 liquidity;
int24 tick;
int24 lowerTick;
int24 upperTick;
}
struct ModifyPosition {
uint256 tokenId;
uint256 proportion;
}
struct SwapPayload {
bytes payload;
address router;
uint256 amountIn;
uint256 expectedMinReturn;
bool zeroForOne;
}
struct RebalanceParams {
ModifyPosition[] decreasePositions;
ModifyPosition[] increasePositions;
SwapPayload swapPayload;
INonfungiblePositionManager.MintParams[] mintParams;
uint256 minBurn0;
uint256 minBurn1;
uint256 minDeposit0;
uint256 minDeposit1;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/// @title Contains 512-bit math functions
/// @notice Facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision
/// @dev Handles "phantom overflow" i.e., allows multiplication and division where an intermediate value overflows 256 bits
library FullMath {
/// @notice Calculates floor(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
/// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv
function mulDiv(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = a * b
// Compute the product mod 2**256 and mod 2**256 - 1
// then 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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(a, b, not(0))
prod0 := mul(a, b)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division
if (prod1 == 0) {
require(denominator > 0);
assembly {
result := div(prod0, denominator)
}
return result;
}
// Make sure the result is less than 2**256.
// Also prevents denominator == 0
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0]
// Compute remainder using mulmod
uint256 remainder;
assembly {
remainder := mulmod(a, b, denominator)
}
// Subtract 256 bit number from 512 bit number
assembly {
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator
// Compute largest power of two divisor of denominator.
// Always >= 1.
// EDIT for 0.8 compatibility:
// see: https://ethereum.stackexchange.com/questions/96642/unary-operator-cannot-be-applied-to-type-uint256
uint256 twos = denominator & (~denominator + 1);
// Divide denominator by power of two
assembly {
denominator := div(denominator, twos)
}
// Divide [prod1 prod0] by the factors of two
assembly {
prod0 := div(prod0, twos)
}
// Shift in bits from prod1 into prod0. For this we need
// to flip `twos` such that it is 2**256 / twos.
// If twos is zero, then it becomes one
assembly {
twos := add(div(sub(0, twos), twos), 1)
}
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
// correct for four bits. That is, denominator * inv = 1 mod 2**4
uint256 inv = (3 * denominator) ^ 2;
// Now use 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.
inv *= 2 - denominator * inv; // inverse mod 2**8
inv *= 2 - denominator * inv; // inverse mod 2**16
inv *= 2 - denominator * inv; // inverse mod 2**32
inv *= 2 - denominator * inv; // inverse mod 2**64
inv *= 2 - denominator * inv; // inverse mod 2**128
inv *= 2 - denominator * inv; // 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 precoditions 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 * inv;
return result;
}
}
/// @notice Calculates ceil(a×b÷denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
/// @param a The multiplicand
/// @param b The multiplier
/// @param denominator The divisor
/// @return result The 256-bit result
function mulDivRoundingUp(
uint256 a,
uint256 b,
uint256 denominator
) internal pure returns (uint256 result) {
result = mulDiv(a, b, denominator);
if (mulmod(a, b, denominator) > 0) {
require(result < type(uint256).max);
result++;
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
import {FullMath} from "./FullMath.sol";
import {FixedPoint96} from "@uniswap/v3-core/contracts/libraries/FixedPoint96.sol";
/// @title Liquidity amount functions
/// @notice Provides functions for computing liquidity amounts from token amounts and prices
library LiquidityAmounts {
function toUint128(uint256 x) private pure returns (uint128 y) {
require((y = uint128(x)) == x);
}
/// @notice Computes the amount of liquidity received for a given amount of token0 and price range
/// @dev Calculates amount0 * (sqrt(upper) * sqrt(lower)) / (sqrt(upper) - sqrt(lower)).
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param amount0 The amount0 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount0(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96)
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
uint256 intermediate = FullMath.mulDiv(
sqrtRatioAX96,
sqrtRatioBX96,
FixedPoint96.Q96
);
return
toUint128(
FullMath.mulDiv(
amount0,
intermediate,
sqrtRatioBX96 - sqrtRatioAX96
)
);
}
/// @notice Computes the amount of liquidity received for a given amount of token1 and price range
/// @dev Calculates amount1 / (sqrt(upper) - sqrt(lower)).
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param amount1 The amount1 being sent in
/// @return liquidity The amount of returned liquidity
function getLiquidityForAmount1(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96)
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return
toUint128(
FullMath.mulDiv(
amount1,
FixedPoint96.Q96,
sqrtRatioBX96 - sqrtRatioAX96
)
);
}
/// @notice Computes the maximum amount of liquidity received for a given amount of token0, token1, the current
/// pool prices and the prices at the tick boundaries
function getLiquidityForAmounts(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint256 amount0,
uint256 amount1
) internal pure returns (uint128 liquidity) {
if (sqrtRatioAX96 > sqrtRatioBX96)
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
liquidity = getLiquidityForAmount0(
sqrtRatioAX96,
sqrtRatioBX96,
amount0
);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
uint128 liquidity0 = getLiquidityForAmount0(
sqrtRatioX96,
sqrtRatioBX96,
amount0
);
uint128 liquidity1 = getLiquidityForAmount1(
sqrtRatioAX96,
sqrtRatioX96,
amount1
);
liquidity = liquidity0 < liquidity1 ? liquidity0 : liquidity1;
} else {
liquidity = getLiquidityForAmount1(
sqrtRatioAX96,
sqrtRatioBX96,
amount1
);
}
}
/// @notice Computes the amount of token0 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param liquidity The liquidity being valued
/// @return amount0 The amount0
function getAmount0ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0) {
if (sqrtRatioAX96 > sqrtRatioBX96)
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return
FullMath.mulDiv(
uint256(liquidity) << FixedPoint96.RESOLUTION,
sqrtRatioBX96 - sqrtRatioAX96,
sqrtRatioBX96
) / sqrtRatioAX96;
}
/// @notice Computes the amount of token1 for a given amount of liquidity and a price range
/// @param sqrtRatioAX96 A sqrt price
/// @param sqrtRatioBX96 Another sqrt price
/// @param liquidity The liquidity being valued
/// @return amount1 The amount1
function getAmount1ForLiquidity(
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96)
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
return
FullMath.mulDiv(
liquidity,
sqrtRatioBX96 - sqrtRatioAX96,
FixedPoint96.Q96
);
}
/// @notice Computes the token0 and token1 value for a given amount of liquidity, the current
/// pool prices and the prices at the tick boundaries
function getAmountsForLiquidity(
uint160 sqrtRatioX96,
uint160 sqrtRatioAX96,
uint160 sqrtRatioBX96,
uint128 liquidity
) internal pure returns (uint256 amount0, uint256 amount1) {
if (sqrtRatioAX96 > sqrtRatioBX96)
(sqrtRatioAX96, sqrtRatioBX96) = (sqrtRatioBX96, sqrtRatioAX96);
if (sqrtRatioX96 <= sqrtRatioAX96) {
amount0 = getAmount0ForLiquidity(
sqrtRatioAX96,
sqrtRatioBX96,
liquidity
);
} else if (sqrtRatioX96 < sqrtRatioBX96) {
amount0 = getAmount0ForLiquidity(
sqrtRatioX96,
sqrtRatioBX96,
liquidity
);
amount1 = getAmount1ForLiquidity(
sqrtRatioAX96,
sqrtRatioX96,
liquidity
);
} else {
amount1 = getAmount1ForLiquidity(
sqrtRatioAX96,
sqrtRatioBX96,
liquidity
);
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO =
1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick)
internal
pure
returns (uint160 sqrtPriceX96)
{
uint256 absTick = tick < 0
? uint256(-int256(tick))
: uint256(int256(tick));
// EDIT: 0.8 compatibility
require(absTick <= uint256(int256(MAX_TICK)), "T");
uint256 ratio = absTick & 0x1 != 0
? 0xfffcb933bd6fad37aa2d162d1a594001
: 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0)
ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0)
ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0)
ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0)
ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0)
ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0)
ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0)
ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0)
ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0)
ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0)
ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0)
ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0)
ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0)
ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0)
ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0)
ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0)
ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0)
ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0)
ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0)
ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX96 = uint160(
(ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1)
);
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint160 sqrtPriceX96)
internal
pure
returns (int24 tick)
{
// second inequality must be < because the price can never reach the price at the max tick
require(
sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO,
"R"
);
uint256 ratio = uint256(sqrtPriceX96) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
int24 tickLow = int24(
(log_sqrt10001 - 3402992956809132418596140100660247210) >> 128
);
int24 tickHi = int24(
(log_sqrt10001 + 291339464771989622907027621153398088495) >> 128
);
tick = tickLow == tickHi
? tickLow
: getSqrtRatioAtTick(tickHi) <= sqrtPriceX96
? tickHi
: tickLow;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal onlyInitializing {
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal onlyInitializing {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
require(!paused(), "Pausable: paused");
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
require(paused(), "Pausable: not paused");
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @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
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
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
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
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
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
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
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
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
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
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
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
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
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
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
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
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
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
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
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
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
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
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
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
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
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
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
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
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
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
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
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
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
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
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
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
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
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
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
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
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
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
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
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
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
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
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
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
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
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
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
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
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
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
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
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
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
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
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
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
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
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
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
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @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
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @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
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (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; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
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.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 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.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
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 (rounding == Rounding.Up && 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 down.
*
* 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 + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* 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 + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
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: GPL-2.0-or-later
pragma solidity >=0.4.0;
/// @title FixedPoint96
/// @notice A library for handling binary fixed point numbers, see https://en.wikipedia.org/wiki/Q_(number_format)
/// @dev Used in SqrtPriceMath.sol
library FixedPoint96 {
uint8 internal constant RESOLUTION = 96;
uint256 internal constant Q96 = 0x1000000000000000000000000;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@solady/contracts/=lib/solady/src/",
"@create3/contracts/=lib/create3/contracts/",
"@v3-lib-0.8/contracts/=lib/v3-lib-0.8/contracts/",
"forge-std/=lib/forge-std/src/",
"@valantis-hot/contracts/=lib/valantis-hot/src/",
"@valantis-core/contracts/=lib/valantis-hot/lib/valantis-core/src/",
"@valantis-hot/contracts-test/=lib/valantis-hot/test/",
"@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/",
"@uniswap/v4-periphery/=lib/v4-periphery/",
"@ensdomains/=lib/v4-periphery/lib/v4-core/node_modules/@ensdomains/",
"@uniswap/v3-core/=lib/valantis-hot/lib/v3-core/",
"@uniswap/v3-periphery/=lib/valantis-hot/lib/v3-periphery/",
"create3/=lib/create3/contracts/",
"doppler-hook/=lib/doppler-hook/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-gas-snapshot/=lib/v4-periphery/lib/forge-gas-snapshot/src/",
"hardhat/=lib/v4-periphery/lib/v4-core/node_modules/hardhat/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"permit2/=lib/v4-periphery/lib/permit2/",
"solady/=lib/solady/",
"solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/",
"v3-core/=lib/valantis-hot/lib/v3-core/contracts/",
"v3-lib-0.8/=lib/v3-lib-0.8/contracts/",
"v3-periphery/=lib/valantis-hot/lib/v3-periphery/contracts/",
"v4-core/=lib/v4-periphery/lib/v4-core/src/",
"v4-periphery/=lib/v4-periphery/",
"valantis-core/=lib/valantis-hot/lib/valantis-core/",
"valantis-hot/=lib/valantis-hot/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"nftPositionManager_","type":"address"},{"internalType":"address","name":"factory_","type":"address"},{"internalType":"address","name":"voter_","type":"address"},{"internalType":"address","name":"guardian_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AEROTokenNotSupported","type":"error"},{"inputs":[],"name":"AddressZero","type":"error"},{"inputs":[],"name":"AmountsZero","type":"error"},{"inputs":[],"name":"BurnToken0","type":"error"},{"inputs":[],"name":"BurnToken1","type":"error"},{"inputs":[],"name":"DepositZero","type":"error"},{"inputs":[],"name":"ExpectedMinReturnTooLow","type":"error"},{"inputs":[],"name":"GaugeKilled","type":"error"},{"inputs":[],"name":"InitsAreZeros","type":"error"},{"inputs":[],"name":"MaxSlippageGtTenPercent","type":"error"},{"inputs":[],"name":"MintToken0","type":"error"},{"inputs":[],"name":"MintToken1","type":"error"},{"inputs":[],"name":"NativeCoinNotSupported","type":"error"},{"inputs":[{"internalType":"uint256","name":"newFees","type":"uint256"}],"name":"NewFeesGtPIPS","type":"error"},{"inputs":[],"name":"OnlyGuardian","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"manager","type":"address"}],"name":"OnlyManager","type":"error"},{"inputs":[],"name":"OnlyManagerOwner","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"metaVault","type":"address"}],"name":"OnlyMetaVault","type":"error"},{"inputs":[],"name":"OnlyMetaVaultOwner","type":"error"},{"inputs":[],"name":"OverMaxDeviation","type":"error"},{"inputs":[],"name":"PoolNotFound","type":"error"},{"inputs":[],"name":"ProportionGtBASE","type":"error"},{"inputs":[],"name":"ProportionZero","type":"error"},{"inputs":[],"name":"SameManagerFee","type":"error"},{"inputs":[],"name":"SameReceiver","type":"error"},{"inputs":[],"name":"SlippageTooHigh","type":"error"},{"inputs":[],"name":"TickSpacingMismatch","type":"error"},{"inputs":[],"name":"Token0Mismatch","type":"error"},{"inputs":[],"name":"Token1Mismatch","type":"error"},{"inputs":[],"name":"TokenIdNotFound","type":"error"},{"inputs":[],"name":"WrongRouter","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"LogApproval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"aeroAmount","type":"uint256"}],"name":"LogClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"LogFund","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"aeroAmount","type":"uint256"}],"name":"LogManagerClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"burn0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"burn1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mint0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mint1","type":"uint256"}],"name":"LogRebalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"LogSetManagerFeePIPS","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldReceiver","type":"address"},{"indexed":false,"internalType":"address","name":"newReceiver","type":"address"}],"name":"LogSetReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"proportion","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"LogWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"}],"name":"LogWithdrawManagerBalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AERO","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aeroManagerBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aeroReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"amount0_","type":"uint256"},{"internalType":"uint256","name":"amount1_","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IUniswapV3Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"depositor_","type":"address"},{"internalType":"uint256","name":"amount0_","type":"uint256"},{"internalType":"uint256","name":"amount1_","type":"uint256"}],"name":"fund","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getInits","outputs":[{"internalType":"uint256","name":"init0","type":"uint256"},{"internalType":"uint256","name":"init1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"id","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IOracleWrapper","name":"oracle_","type":"address"},{"internalType":"uint24","name":"maxSlippage_","type":"uint24"},{"internalType":"address","name":"aeroReceiver_","type":"address"},{"internalType":"int24","name":"tickSpacing_","type":"int24"},{"internalType":"address","name":"metaVault_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"initializePosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"managerBalance0","outputs":[{"internalType":"uint256","name":"managerFee0","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerBalance1","outputs":[{"internalType":"uint256","name":"managerFee1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"managerFeePIPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSlippage","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metaVault","outputs":[{"internalType":"contract IArrakisMetaVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nftPositionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracleWrapper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"proportion","type":"uint256"}],"internalType":"struct ModifyPosition[]","name":"decreasePositions","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"proportion","type":"uint256"}],"internalType":"struct ModifyPosition[]","name":"increasePositions","type":"tuple[]"},{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"address","name":"router","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"expectedMinReturn","type":"uint256"},{"internalType":"bool","name":"zeroForOne","type":"bool"}],"internalType":"struct SwapPayload","name":"swapPayload","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"int24","name":"tickSpacing","type":"int24"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint160","name":"sqrtPriceX96","type":"uint160"}],"internalType":"struct INonfungiblePositionManager.MintParams[]","name":"mintParams","type":"tuple[]"},{"internalType":"uint256","name":"minBurn0","type":"uint256"},{"internalType":"uint256","name":"minBurn1","type":"uint256"},{"internalType":"uint256","name":"minDeposit0","type":"uint256"},{"internalType":"uint256","name":"minDeposit1","type":"uint256"}],"internalType":"struct RebalanceParams","name":"params_","type":"tuple"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeePIPS_","type":"uint256"}],"name":"setManagerFeePIPS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newReceiver_","type":"address"}],"name":"setReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"contract IERC20Metadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlying","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint160","name":"priceX96_","type":"uint160"}],"name":"totalUnderlyingAtPrice","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOracleWrapper","name":"oracle_","type":"address"},{"internalType":"uint24","name":"maxDeviation_","type":"uint24"}],"name":"validateRebalance","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voter","outputs":[{"internalType":"contract IVoter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"proportion_","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawManagerBalance","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610100604052348015610010575f80fd5b50604051615b9a380380615b9a83398101604081905261002f91610195565b6001600160a01b038416158061004c57506001600160a01b038316155b8061005e57506001600160a01b038216155b8061007057506001600160a01b038116155b1561008e57604051639fabe1c160e01b815260040160405180910390fd5b6001600160a01b0380851660a05283811660c05282811660e05281166080526100b56100be565b505050506101e6565b5f54610100900460ff16156101295760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811614610178575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b80516001600160a01b0381168114610190575f80fd5b919050565b5f805f80608085870312156101a8575f80fd5b6101b18561017a565b93506101bf6020860161017a565b92506101cd6040860161017a565b91506101db6060860161017a565b905092959194509250565b60805160a05160c05160e0516158e06102ba5f395f81816103a301528181612e050152612e9201525f81816105d70152612d5001525f81816104be01528181611ab4015281816134550152818161352d015281816135cb0152818161366701528181613996015281816139db01528181613a4801528181613ada01528181613b1801528181613b6801528181613d6201528181613da401528181613de401528181613e7b01528181613eb901528181613f16015261427d01525f818161098101528181610b6f0152610f3f01526158e05ff3fe60806040526004361061021d575f3560e01c80637ecd67171161011e578063c45a0155116100a8578063dce4312b1161006d578063dce4312b1461065e578063e0be9cfd1461067d578063ef5cfb8c14610692578063f3fef3a3146106b1578063f96ac622146106d0575f80fd5b8063c45a0155146105c6578063c6b29347146105f9578063c70920bc1461060c578063d21220a714610620578063d677d8681461063f575f80fd5b8063a6f19c84116100ee578063a6f19c8414610523578063a9a36dcd14610542578063acecf6f514610556578063af640d0f14610575578063c40394d3146105a8575f80fd5b80637ecd67171461048457806384397888146104ad5780638456cb59146104e05780638c04166f146104f4575f80fd5b8063426a8493116101aa5780635c975abb1161016f5780635c975abb146103e4578063714cff5614610406578063718da7ee1461042757806378df8e70146104465780637dc0d1d014610465575f80fd5b8063426a84931461035f57806342fb9d4414610221578063452a93201461037e57806346c96aac146103925780635933599a146103c5575f80fd5b80630e2e9b0f116101f05780630e2e9b0f146102a2578063150b7a02146102c85780631691bd6f1461030c57806316f0115b1461032c5780633f4ba83a1461034b575f80fd5b8063065756db1461022157806308c6ef08146102425780630af6ce85146102565780630dfe16811461026b575b5f80fd5b34801561022c575f80fd5b505f5b6040519081526020015b60405180910390f35b34801561024d575f80fd5b5061022f6106ef565b610269610264366004614dff565b610845565b005b348015610276575f80fd5b5060985461028a906001600160a01b031681565b6040516001600160a01b039091168152602001610239565b3480156102ad575f80fd5b50609c5461028a90630100000090046001600160a01b031681565b3480156102d3575f80fd5b506102f36102e2366004614e76565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610239565b348015610317575f80fd5b5061028a5f8051602061586683398151915281565b348015610337575f80fd5b50609d5461028a906001600160a01b031681565b348015610356575f80fd5b50610269610976565b34801561036a575f80fd5b50610269610379366004614dff565b610a35565b348015610389575f80fd5b5061028a610b6c565b34801561039d575f80fd5b5061028a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d0575f80fd5b506102696103df366004614ee4565b610bf2565b3480156103ef575f80fd5b5060335460ff166040519015158152602001610239565b348015610411575f80fd5b5061041a610d37565b6040516102399190614efb565b348015610432575f80fd5b50610269610441366004614f3d565b610d43565b348015610451575f80fd5b5060975461028a906001600160a01b031681565b348015610470575f80fd5b50609a5461028a906001600160a01b031681565b34801561048f575f80fd5b50610498610f14565b60408051928352602083019190915201610239565b3480156104b8575f80fd5b5061028a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104eb575f80fd5b50610269610f34565b3480156104ff575f80fd5b50609c5461050f9062ffffff1681565b60405162ffffff9091168152602001610239565b34801561052e575f80fd5b50609e5461028a906001600160a01b031681565b34801561054d575f80fd5b50610269610ff0565b348015610561575f80fd5b50610498610570366004614f3d565b611225565b348015610580575f80fd5b5061022f7f491defc0794897991a8e5e9fa49dcbed24fe84ee079750b1db3f4df77fb17cb581565b3480156105b3575f80fd5b506102696105c2366004614f58565b5050565b3480156105d1575f80fd5b5061028a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610604575f80fd5b505f80610498565b348015610617575f80fd5b5061049861136d565b34801561062b575f80fd5b5060995461028a906001600160a01b031681565b34801561064a575f80fd5b50610269610659366004614f97565b611531565b348015610669575f80fd5b50610269610678366004614fe1565b61208e565b348015610688575f80fd5b5061022f609b5481565b34801561069d575f80fd5b506102696106ac366004614f3d565b61234d565b3480156106bc575f80fd5b506104986106cb366004615014565b6126c3565b3480156106db575f80fd5b506102696106ea366004615057565b612a16565b5f805f6106fc609f612fc5565b609e549091506001600160a01b03165f5b8281101561081a575f610721609f83612fd4565b604051637980d7a160e11b8152600481018290529091506001600160a01b0384169063f301af4290602401602060405180830381865afa158015610767573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061078b91906150c2565b61079590866150ed565b604051633e491d4760e01b8152306004820152602481018390529095506001600160a01b03841690633e491d4790604401602060405180830381865afa1580156107e1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080591906150c2565b61080f90866150ed565b94505060010161070d565b5061083083609b54620f424062ffffff16612fe6565b60a15461083d91906150ed565b935050505090565b61084d61308b565b6097546001600160a01b031633811461088f57604051635fc5149960e11b81523360048201526001600160a01b03821660248201526044015b60405180910390fd5b6108976130e4565b34156108b6576040516390eed9e960e01b815260040160405180910390fd5b821580156108c2575081155b156108e0576040516378b7ac0360e01b815260040160405180910390fd5b82156108fe576098546108fe906001600160a01b031685308661312a565b811561091c5760995461091c906001600160a01b031685308561312a565b604080516001600160a01b0386168152602081018590529081018390527fb6b61f73303cc86cb9e6eee7756d1334f129e7711d778aa201fb3fa611dfe6dd9060600160405180910390a1506109716001606555565b505050565b61097e6131a2565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639fd0506d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ff9190615100565b90506001600160a01b0381163314610a2a57604051636570ecab60e11b815260040160405180910390fd5b610a326131eb565b50565b610a3d61308b565b610a456130e4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a95573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab99190615100565b6001600160a01b0316336001600160a01b031614610aea5760405163f68ef6bf60e01b815260040160405180910390fd5b6098546099546001600160a01b039182169116610b0882868661323d565b610b1c6001600160a01b038216868561323d565b60408051858152602081018590526001600160a01b038716917f300cfe37bf342ac8761414ef964d4a4d284b045e489703c08c85b9d1ea64801c910160405180910390a250506109716001606555565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639fd0506d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bed9190615100565b905090565b6097546040805163481c6a7560e01b815290515f926001600160a01b03169163481c6a759160048083019260209291908290030181865afa158015610c39573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5d9190615100565b90506001600160a01b0381163314610c995760405163167231b360e21b81523360048201526001600160a01b0382166024820152604401610886565b610ca16130e4565b609b54828103610cc45760405163142842f960e11b815260040160405180910390fd5b620f4240831115610ceb576040516335f24c0760e01b815260048101849052602401610886565b610cf3610ff0565b609b83905560408051828152602081018590527f5b5a6a8527892eb1e879279ea1addd664eef55099889d3fe13e926a5fd7c360591015b60405180910390a1505050565b6060610bed609f6132cb565b610d4b6130e4565b6097546040805163481c6a7560e01b815290515f926001600160a01b03169163481c6a759160048083019260209291908290030181865afa158015610d92573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610db69190615100565b9050336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dfe573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e229190615100565b6001600160a01b031614610e4957604051630fc9f84560e11b815260040160405180910390fd5b609c546001600160a01b0363010000009091048116908316610e7e57604051639fabe1c160e01b815260040160405180910390fd5b826001600160a01b0316816001600160a01b031603610eb05760405163fb1dbe5560e01b815260040160405180910390fd5b609c80546301000000600160b81b03191663010000006001600160a01b038681169182029290921790925560408051918416825260208201929092527f80f0c3fe8b42050f13c290b2651f6499bda92e8864245df1c14f1604851d61809101610d2a565b5f80610f1e61308b565b610f266130e4565b610f306001606555565b9091565b610f3c6130e4565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639fd0506d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f99573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fbd9190615100565b90506001600160a01b0381163314610fe857604051636570ecab60e11b815260040160405180910390fd5b610a326132d7565b610ff861308b565b6110006130e4565b5f61100b609f612fc5565b609e546040516370a0823160e01b81523060048201529192506001600160a01b0316905f905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015611063573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108791906150c2565b90505f5b83811015611103575f61109f609f83612fd4565b604051631c4b774b60e01b8152600481018290529091506001600160a01b03851690631c4b774b906024015f604051808303815f87803b1580156110e1575f80fd5b505af11580156110f3573d5f803e3d5ffd5b505050506001820191505061108b565b506040516370a0823160e01b815230600482015281905f80516020615866833981519152906370a0823190602401602060405180830381865afa15801561114c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061117091906150c2565b61117a919061511b565b90505f61119282609b54620f424062ffffff16612fe6565b60a15461119f91906150ed565b5f60a155609c54909150630100000090046001600160a01b03166111d15f805160206158668339815191528284613314565b806001600160a01b03167fb394755410f704d048c51b075262ff71c1049c4a7c48025fc2ccd15d23d5b6778360405161120c91815260200190565b60405180910390a250505050506112236001606555565b565b5f805f611232609f612fc5565b90505f5b8181101561127b575f8061125461124e609f85612fd4565b88613344565b909250905061126382876150ed565b955061126f81866150ed565b94505050600101611236565b506098546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156112c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112e691906150c2565b6112f090846150ed565b6099546040516370a0823160e01b81523060048201529194506001600160a01b0316906370a0823190602401602060405180830381865afa158015611337573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135b91906150c2565b61136590836150ed565b915050915091565b5f805f61137a609f612fc5565b90505f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156113cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113f1919061514c565b505050505090505f5b8281101561143f575f80611418611412609f85612fd4565b85613344565b909250905061142782886150ed565b965061143381876150ed565b955050506001016113fa565b506098546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611486573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114aa91906150c2565b6114b490856150ed565b6099546040516370a0823160e01b81523060048201529195506001600160a01b0316906370a0823190602401602060405180830381865afa1580156114fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061151f91906150c2565b61152990846150ed565b925050509091565b61153961308b565b6115416130e4565b6097546040805163481c6a7560e01b815290515f926001600160a01b03169163481c6a759160048083019260209291908290030181865afa158015611588573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115ac9190615100565b90506001600160a01b03811633146115e85760405163167231b360e21b81523360048201526001600160a01b0382166024820152604401610886565b5f6115f383806151c5565b905090505f805f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa15801561164a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166e919061514c565b505050505090505f8411156117bd57609b545f90815b8681101561174c576116ba6116998a806151c5565b838181106116a9576116a961520b565b609f92604090910201359050613382565b6116d757604051637ec8def360e11b815260040160405180910390fd5b5f80806117136116e78d806151c5565b868181106116f7576116f761520b565b90506040020180360381019061170d919061521f565b88613399565b91945092509050611724838a6150ed565b985061173082896150ed565b975061173c81876150ed565b9550600184019350505050611684565b5061175b8282620f4240612fe6565b60a15f82825461176b91906150ed565b9091555050608088013585101561179557604051632b0bd3a160e21b815260040160405180910390fd5b8760a001358410156117ba57604051630d517e6760e01b815260040160405180910390fd5b50505b5f6117cb604088018861527a565b604001351115611de9576098546099546001600160a01b0391821691166118f06117f860408a018a61527a565b6118099060a0810190608001615298565b61181660408b018b61527a565b6060013561182760408c018c61527a565b60400135856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611867573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061188b91906152b3565b856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118eb91906152b3565b613722565b5f6118fe60408a018a61527a565b61190f9060a0810190608001615298565b156119c45761195761192460408b018b61527a565b611935906040810190602001614f3d565b61194260408c018c61527a565b6001600160a01b03861691906040013561323d565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611999573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119bd91906150c2565b9050611a70565b611a076119d460408b018b61527a565b6119e5906040810190602001614f3d565b6119f260408c018c61527a565b6001600160a01b03851691906040013561323d565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611a49573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a6d91906150c2565b90505b6097546001600160a01b0316611a8960408b018b61527a565b611a9a906040810190602001614f3d565b6001600160a01b03161480611afd57506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016611ae160408b018b61527a565b611af2906040810190602001614f3d565b6001600160a01b0316145b80611b385750609e546001600160a01b0316611b1c60408b018b61527a565b611b2d906040810190602001614f3d565b6001600160a01b0316145b80611b7557505f80516020615866833981519152611b5960408b018b61527a565b611b6a906040810190602001614f3d565b6001600160a01b0316145b15611b93576040516364ec5f9b60e01b815260040160405180910390fd5b611c0e611ba360408b018b61527a565b611bad90806152d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611bee9250505060408c018c61527a565b611bff906040810190602001614f3d565b6001600160a01b03169061386f565b50611c1c60408a018a61527a565b611c2d9060a0810190608001615298565b15611d0e576040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015611c76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c9a91906150c2565b611ca4919061511b565b905080611cb460408b018b61527a565b606001351115611cd75760405163428637bb60e11b815260040160405180910390fd5b611d09611ce760408b018b61527a565b611cf8906040810190602001614f3d565b6001600160a01b038516905f61323d565b611de5565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015611d52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d7691906150c2565b611d80919061511b565b905080611d9060408b018b61527a565b606001351115611db35760405163428637bb60e11b815260040160405180910390fd5b611de5611dc360408b018b61527a565b611dd4906040810190602001614f3d565b6001600160a01b038416905f61323d565b5050505b5f80609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa158015611e3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e5f919061514c565b50939650611e769350505060208a019050896151c5565b9650508515611f5d57609b545f90815b88811015611f3657611e9e61169960208d018d6151c5565b611ebb57604051637ec8def360e11b815260040160405180910390fd5b5f805f611efd8e8060200190611ed191906151c5565b86818110611ee157611ee161520b565b905060400201803603810190611ef7919061521f565b8a6138b2565b91945092509050611f0e83896150ed565b9750611f1a82886150ed565b9650611f2681876150ed565b9550600184019350505050611e86565b50611f458282620f4240612fe6565b60a15f828254611f5591906150ed565b909155505050505b611f6a6060890189615316565b9650508515612035576098546099546001600160a01b0391821691165f5b88811015611fe7575f80611fc0611fa260608f018f615316565b85818110611fb257611fb261520b565b905061018002018686613c24565b9092509050611fcf82886150ed565b9650611fdb81876150ed565b95505050600101611f88565b508960c0013584101561200d5760405163ed8bd62d60e01b815260040160405180910390fd5b8960e00135831015612032576040516342a96c6d60e11b815260040160405180910390fd5b50505b6040805186815260208101869052908101839052606081018290527f297b58c128b54f4e5041ecc8d817795f247871ea6cb93bd6f8d1db646d1b47249060800160405180910390a150505050505050610a326001606555565b6098546099546040805163313ce56760e01b815290516001600160a01b0393841693909216915f91849163313ce567916004808201926020929091908290030181865afa1580156120e1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210591906152b3565b90505f826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612144573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061216891906152b3565b90505f866001600160a01b031663e84b8fe56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121cb91906150c2565b90505f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa15801561221e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612242919061514c565b505050505090505f6001600160801b038016826001600160a01b0316116122955761228e6122796001600160a01b0384168061535c565b61228487600a615456565b600160c01b612fe6565b90506122cd565b6122ca6122b56001600160a01b0384168068010000000000000000612fe6565b6122c087600a615456565b600160801b612fe6565b90505b5f6123196123058584116122ea576122e5848761511b565b6122f4565b6122f4868561511b565b6122ff88600a615456565b85612fe6565b620f424061231488600a615456565b612fe6565b90508862ffffff168111156123415760405163371446a760e21b815260040160405180910390fd5b50505050505050505050565b60975f9054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561239d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c19190615100565b6001600160a01b0316336001600160a01b0316146123f25760405163f68ef6bf60e01b815260040160405180910390fd5b6123fa61308b565b6124026130e4565b6001600160a01b03811661242957604051639fabe1c160e01b815260040160405180910390fd5b5f612434609f612fc5565b609e546040516370a0823160e01b81523060048201529192505f916001600160a01b039091169082905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015612490573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124b491906150c2565b90505f5b84811015612530575f6124cc609f83612fd4565b604051631c4b774b60e01b8152600481018290529091506001600160a01b03851690631c4b774b906024015f604051808303815f87803b15801561250e575f80fd5b505af1158015612520573d5f803e3d5ffd5b50505050600182019150506124b8565b506040516370a0823160e01b815230600482015281905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015612579573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061259d91906150c2565b6125a7919061511b565b6125b190846150ed565b92506125c883609b54620f424062ffffff16612fe6565b60a15f8282546125d891906150ed565b909155505060a1546040516370a0823160e01b81523060048201525f91905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015612629573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061264d91906150c2565b612657919061511b565b90506126715f805160206158668339815191528783613314565b856001600160a01b03167ffce6d5860f911bc27ece1365300332d2ddbe20c1adc46ee2eddd8f72c48053b2826040516126ac91815260200190565b60405180910390a25050505050610a326001606555565b6097545f9081906001600160a01b031633811461270457604051635fc5149960e11b81523360048201526001600160a01b0382166024820152604401610886565b61270c61308b565b6001600160a01b03851661273357604051639fabe1c160e01b815260040160405180910390fd5b835f03612753576040516398c5be9760e01b815260040160405180910390fd5b670de0b6b3a764000084111561277c57604051632139c5c160e01b815260040160405180910390fd5b5f612787609f6132cb565b6098546099546040516370a0823160e01b81523060048201529293505f926001600160a01b0392831692909116906128139083906370a08231906024015b602060405180830381865afa1580156127e0573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061280491906150c2565b89670de0b6b3a7640000612fe6565b6040516370a0823160e01b8152306004820152909750612846906001600160a01b038316906370a08231906024016127c5565b95505f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa158015612899573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128bd919061514c565b505050505090506128df60405180604001604052805f81526020015f81525090565b602081018a90525f5b8651811015612956578681815181106129035761290361520b565b602090810291909101015182525f808061291d8587613399565b9194509250905061292e838e6150ed565b9c5061293a828d6150ed565b9b50612946818a6150ed565b98506001840193505050506128e8565b50609b546129688682620f4240612fe6565b60a15f82825461297891906150ed565b90915550508915612997576129976001600160a01b0386168d8c613314565b88156129b1576129b16001600160a01b0385168d8b613314565b604080518c8152602081018c90529081018a90526001600160a01b038d16907f9744d0a120f7c7d7906cfe3c05b50669fb49aa6d778b099d5d6edc386dee5b599060600160405180910390a250505050505050612a0e6001606555565b509250929050565b5f54610100900460ff1615808015612a3457505f54600160ff909116105b80612a4d5750303b158015612a4d57505f5460ff166001145b612ab05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610886565b5f805460ff191660011790558015612ad1575f805461ff0019166101001790555b6001600160a01b0382161580612aee57506001600160a01b038616155b80612b0057506001600160a01b038416155b15612b1e57604051639fabe1c160e01b815260040160405180910390fd5b620186a062ffffff86161115612b475760405163198a0acd60e31b815260040160405180910390fd5b609780546001600160a01b038085166001600160a01b03199283168117909355609a80548a8316931692909217909155609c80549187166301000000026001600160b81b031990921662ffffff89161791909117905560408051630dfe168160e01b815290515f9291630dfe16819160048083019260209291908290030181865afa158015612bd8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bfc9190615100565b90505f836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c5f9190615100565b90506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480612ca857506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612cc6576040516390eed9e960e01b815260040160405180910390fd5b6001600160a01b0382165f805160206158668339815191521480612cff57506001600160a01b0381165f80516020615866833981519152145b15612d1d57604051631887580f60e21b815260040160405180910390fd5b6040516328af8d0b60e01b81526001600160a01b0383811660048301528281166024830152600287900b60448301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906328af8d0b90606401602060405180830381865afa158015612d97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612dbb9190615100565b90506001600160a01b038116612de4576040516301dbb3ff60e61b815260040160405180910390fd5b60405163b9a09fd560e01b81526001600160a01b0382811660048301525f917f00000000000000000000000000000000000000000000000000000000000000009091169063b9a09fd590602401602060405180830381865afa158015612e4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e709190615100565b604051631703e5f960e01b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690631703e5f990602401602060405180830381865afa158015612ed9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612efd9190615464565b612f1a5760405163039b284d60e31b815260040160405180910390fd5b609d80546001600160a01b038085166001600160a01b031992831617909255609e8054848416908316179055609880548784169083161790556099805492861692909116919091179055612f6c613fcd565b612f74613ffb565b505050508015612fbd575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b5f612fce825490565b92915050565b5f612fdf8383614029565b9392505050565b5f80805f19858709858702925082811083820303915050805f0361301a575f841161300f575f80fd5b508290049050612fdf565b808411613025575f80fd5b5f84868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203025f889003889004909101858311909403939093029303949094049190911702949350505050565b6002606554036130dd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610886565b6002606555565b60335460ff16156112235760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610886565b6040516001600160a01b03808516602483015283166044820152606481018290526131959085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261404f565b50505050565b6001606555565b60335460ff166112235760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610886565b6131f36131a2565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261328e8482614122565b613195576040516001600160a01b03841660248201525f60448201526132c190859063095ea7b360e01b9060640161315e565b613195848261404f565b60605f612fdf836141c3565b6132df6130e4565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132203390565b6040516001600160a01b03831660248201526044810182905261097190849063a9059cbb60e01b9060640161315e565b5f805f805f6133528761421c565b92509250925061337486613365856142cd565b61336e856142cd565b846146e6565b909890975095505050505050565b5f8181526001830160205260408120541515612fdf565b5f805f805f806133ab885f0151614781565b909450925090506133bc81856150ed565b9350506133e76133e2826001600160801b03168960200151670de0b6b3a7640000612fe6565b6148f0565b6040805160a081018252895181526001600160801b03838116602083019081525f838501818152606085019182525f19608086019081529551630624e65f60e11b815285516004820152925190931660248301529151604482015290516064820152915160848301529192507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630c49ccbe9060a40160408051808303815f875af11580156134a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134c6919061547f565b5050604080516080810182528951815230602082019081526001600160801b0382840181815260608401828152945163fc6f786560e01b81529351600485015291516001600160a01b039081166024850152915181166044840152925190921660648201527f0000000000000000000000000000000000000000000000000000000000000000909116915063fc6f78659060840160408051808303815f875af1158015613575573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613599919061547f565b60208901519196509450670de0b6b3a763ffff190161363e578651604051630852cd8d60e31b815260048101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c68906024015f604051808303815f87803b158015613614575f80fd5b505af1158015613626573d5f803e3d5ffd5b505088516136389250609f915061495c565b50613719565b865160405163095ea7b360e01b81526001600160a01b03848116600483015260248201929092527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044015f604051808303815f87803b1580156136aa575f80fd5b505af11580156136bc573d5f803e3d5ffd5b5050885160405163b6b55f2560e01b815260048101919091526001600160a01b038516925063b6b55f2591506024015f604051808303815f87803b158015613702575f80fd5b505af1158015613714573d5f803e3d5ffd5b505050505b50509250925092565b84156137f157609a546040805163e84b8fe560e01b815290516137b8926001600160a01b03169163e84b8fe59160048083019260209291908290030181865afa158015613771573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061379591906150c2565b609c546137aa9062ffffff16620f42406154a1565b62ffffff16620f4240612fe6565b6137cd856137c785600a615456565b86612fe6565b10156137ec57604051634e7ce55560e01b815260040160405180910390fd5b613868565b609a546040805163a941ada960e01b8152905161383a926001600160a01b03169163a941ada99160048083019260209291908290030181865afa158015613771573d5f803e3d5ffd5b613849856137c784600a615456565b101561386857604051634e7ce55560e01b815260040160405180910390fd5b5050505050565b6060612fdf83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250614967565b5f805f805f6138c4875f015187613344565b885191935091505f9081906138d890614781565b50925090506138e781866150ed565b9450506139046133e2848a60200151670de0b6b3a7640000612fe6565b6001600160801b031692506139296133e2838a60200151670de0b6b3a7640000612fe6565b6040805160c0810182528a518152602081018690526001600160801b03929092169082018190525f6060830181905260808301525f1960a08301526098546099549194506001600160a01b03908116911685156139bb5760208301516139bb906001600160a01b038416907f00000000000000000000000000000000000000000000000000000000000000009061323d565b604083015115613a00576040830151613a00906001600160a01b038316907f00000000000000000000000000000000000000000000000000000000000000009061323d565b6040805163219f5d1760e01b81528451600482015260208501516024820152908401516044820152606084015160648201526080840151608482015260a084015160a48201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063219f5d179060c4016060604051808303815f875af1158015613a96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613aba91906154d2565b6020860151919b509950159050613aff57613aff6001600160a01b0383167f00000000000000000000000000000000000000000000000000000000000000005f61323d565b604083015115613b3d57613b3d6001600160a01b0382167f00000000000000000000000000000000000000000000000000000000000000005f61323d565b5050885160405163095ea7b360e01b81526001600160a01b03848116600483015260248201929092527f0000000000000000000000000000000000000000000000000000000000000000909116915063095ea7b3906044015f604051808303815f87803b158015613bac575f80fd5b505af1158015613bbe573d5f803e3d5ffd5b5050895160405163b6b55f2560e01b815260048101919091526001600160a01b038416925063b6b55f2591506024015f604051808303815f87803b158015613c04575f80fd5b505af1158015613c16573d5f803e3d5ffd5b505050505050509250925092565b5f80806001600160a01b038516613c3e6020880188614f3d565b6001600160a01b031614613c6557604051633e2e391b60e11b815260040160405180910390fd5b6001600160a01b038416613c7f6040880160208901614f3d565b6001600160a01b031614613ca65760405163f593f01d60e01b815260040160405180910390fd5b609d54604080516334324e9f60e21b815290515f926001600160a01b03169163d0c93a7c9160048083019260209291908290030181865afa158015613ced573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d119190615504565b9050600281900b613d286060890160408a0161551f565b60020b14613d4957604051637166dcc160e01b815260040160405180910390fd5b60a087013515613d8b57613d8b6001600160a01b0387167f000000000000000000000000000000000000000000000000000000000000000060a08a013561323d565b60c087013515613dcd57613dcd6001600160a01b0386167f000000000000000000000000000000000000000000000000000000000000000060c08a013561323d565b60405163b5007d1f60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b5007d1f90613e19908a9060040161553a565b6080604051808303815f875af1158015613e35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e599190615639565b90965094509092505060a087013515613ea057613ea06001600160a01b0387167f00000000000000000000000000000000000000000000000000000000000000005f61323d565b60c087013515613ede57613ede6001600160a01b0386167f00000000000000000000000000000000000000000000000000000000000000005f61323d565b613ee9609f83614a3e565b50609e5460405163095ea7b360e01b81526001600160a01b039182166004820181905260248201859052917f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b3906044015f604051808303815f87803b158015613f57575f80fd5b505af1158015613f69573d5f803e3d5ffd5b505060405163b6b55f2560e01b8152600481018690526001600160a01b038416925063b6b55f2591506024015f604051808303815f87803b158015613fac575f80fd5b505af1158015613fbe573d5f803e3d5ffd5b50505050505050935093915050565b5f54610100900460ff16613ff35760405162461bcd60e51b815260040161088690615672565b611223614a49565b5f54610100900460ff166140215760405162461bcd60e51b815260040161088690615672565b611223614a6f565b5f825f01828154811061403e5761403e61520b565b905f5260205f200154905092915050565b5f6140a3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614aa19092919063ffffffff16565b905080515f14806140c35750808060200190518101906140c39190615464565b6109715760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610886565b5f805f846001600160a01b03168460405161413d91906156bd565b5f604051808303815f865af19150503d805f8114614176576040519150601f19603f3d011682016040523d82523d5f602084013e61417b565b606091505b50915091508180156141a55750805115806141a55750808060200190518101906141a59190615464565b80156141ba57506001600160a01b0385163b15155b95945050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561421057602002820191905f5260205f20905b8154815260200190600101908083116141fc575b50505050509050919050565b5f805f806399fbab8860e01b8560405160240161423b91815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290505f6142a36001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001683614aaf565b9050808060200190518101906142b991906156d3565b919d909c50909a5098505050505050505050565b5f805f8360020b126142e2578260020b6142ef565b8260020b6142ef90615789565b90506142fe620d89e7196157a3565b60020b8111156143345760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610886565b5f816001165f0361434957600160801b61435b565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561439a576080614395826ffff97272373d413259a46990580e213a61535c565b901c90505b60048216156143c45760806143bf826ffff2e50f5f656932ef12357cf3c7fdcc61535c565b901c90505b60088216156143ee5760806143e9826fffe5caca7e10e4e61c3624eaa0941cd061535c565b901c90505b6010821615614418576080614413826fffcb9843d60f6159c9db58835c92664461535c565b901c90505b602082161561444257608061443d826fff973b41fa98c081472e6896dfb254c061535c565b901c90505b604082161561446c576080614467826fff2ea16466c96a3843ec78b326b5286161535c565b901c90505b6080821615614496576080614491826ffe5dee046a99a2a811c461f1969c305361535c565b901c90505b6101008216156144c15760806144bc826ffcbe86c7900a88aedcffc83b479aa3a461535c565b901c90505b6102008216156144ec5760806144e7826ff987a7253ac413176f2b074cf7815e5461535c565b901c90505b610400821615614517576080614512826ff3392b0822b70005940c7a398e4b70f361535c565b901c90505b61080082161561454257608061453d826fe7159475a2c29b7443b29c7fa6e889d961535c565b901c90505b61100082161561456d576080614568826fd097f3bdfd2022b8845ad8f792aa582561535c565b901c90505b612000821615614598576080614593826fa9f746462d870fdf8a65dc1f90e061e561535c565b901c90505b6140008216156145c35760806145be826f70d869a156d2a1b890bb3df62baf32f761535c565b901c90505b6180008216156145ee5760806145e9826f31be135f97d08fd981231505542fcfa661535c565b901c90505b6201000082161561461a576080614615826f09aa508b5b7a84e1c677de54f3e99bc961535c565b901c90505b62020000821615614645576080614640826e5d6af8dedb81196699c329225ee60461535c565b901c90505b6204000082161561466f57608061466a826d2216e584f5fa1ea926041bedfe9861535c565b901c90505b62080000821615614697576080614692826b048a170391f7dc42444e8fa261535c565b901c90505b5f8460020b13156146b0576146ad815f196157d7565b90505b6146bf640100000000826157ea565b156146cb5760016146cd565b5f5b6146de9060ff16602083901c6150ed565b949350505050565b5f80836001600160a01b0316856001600160a01b03161115614706579293925b846001600160a01b0316866001600160a01b0316116147315761472a858585614ad4565b9150614778565b836001600160a01b0316866001600160a01b0316101561476a57614756868585614ad4565b9150614763858785614b46565b9050614778565b614775858585614b46565b90505b94509492505050565b5f805f61478d8461421c565b609e546040516370a0823160e01b81523060048201526001600160a01b0390911695509093505f92505f8051602061586683398151915291506370a0823190602401602060405180830381865afa1580156147ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061480e91906150c2565b604051632e1a7d4d60e01b8152600481018790529091506001600160a01b03841690632e1a7d4d906024015f604051808303815f87803b158015614850575f80fd5b505af1158015614862573d5f803e3d5ffd5b50506040516370a0823160e01b81523060048201528392505f8051602061586683398151915291506370a0823190602401602060405180830381865afa1580156148ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906148d291906150c2565b6148dc919061511b565b6148e690856150ed565b9350509193909250565b5f6001600160801b038211156149585760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610886565b5090565b5f612fdf8383614b8f565b6060824710156149c85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610886565b5f80866001600160a01b031685876040516149e391906156bd565b5f6040518083038185875af1925050503d805f8114614a1d576040519150601f19603f3d011682016040523d82523d5f602084013e614a22565b606091505b5091509150614a3387838387614c79565b979650505050505050565b5f612fdf8383614cf1565b5f54610100900460ff1661319b5760405162461bcd60e51b815260040161088690615672565b5f54610100900460ff16614a955760405162461bcd60e51b815260040161088690615672565b6033805460ff19169055565b60606146de84845f85614967565b6060612fdf838360405180606001604052806025815260200161588660259139614d3d565b5f826001600160a01b0316846001600160a01b03161115614af3579192915b6001600160a01b038416614b3c6fffffffffffffffffffffffffffffffff60601b606085901b16614b2487876157fd565b6001600160a01b0316866001600160a01b0316612fe6565b6146de91906157d7565b5f826001600160a01b0316846001600160a01b03161115614b65579192915b6146de6001600160801b038316614b7c86866157fd565b6001600160a01b0316600160601b612fe6565b5f8181526001830160205260408120548015614c69575f614bb160018361511b565b85549091505f90614bc49060019061511b565b9050818114614c23575f865f018281548110614be257614be261520b565b905f5260205f200154905080875f018481548110614c0257614c0261520b565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614c3457614c3461581c565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050612fce565b5f915050612fce565b5092915050565b60608315614ce75782515f03614ce0576001600160a01b0385163b614ce05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610886565b50816146de565b6146de8383614db1565b5f818152600183016020526040812054614d3657508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155612fce565b505f612fce565b60605f80856001600160a01b031685604051614d5991906156bd565b5f60405180830381855afa9150503d805f8114614d91576040519150601f19603f3d011682016040523d82523d5f602084013e614d96565b606091505b5091509150614da786838387614c79565b9695505050505050565b815115614dc15781518083602001fd5b8060405162461bcd60e51b81526004016108869190615830565b6001600160a01b0381168114610a32575f80fd5b8035614dfa81614ddb565b919050565b5f805f60608486031215614e11575f80fd5b8335614e1c81614ddb565b95602085013595506040909401359392505050565b5f8083601f840112614e41575f80fd5b50813567ffffffffffffffff811115614e58575f80fd5b602083019150836020828501011115614e6f575f80fd5b9250929050565b5f805f805f60808688031215614e8a575f80fd5b8535614e9581614ddb565b94506020860135614ea581614ddb565b935060408601359250606086013567ffffffffffffffff811115614ec7575f80fd5b614ed388828901614e31565b969995985093965092949392505050565b5f60208284031215614ef4575f80fd5b5035919050565b602080825282518282018190525f918401906040840190835b81811015614f32578351835260209384019390920191600101614f14565b509095945050505050565b5f60208284031215614f4d575f80fd5b8135612fdf81614ddb565b5f8060208385031215614f69575f80fd5b823567ffffffffffffffff811115614f7f575f80fd5b614f8b85828601614e31565b90969095509350505050565b5f60208284031215614fa7575f80fd5b813567ffffffffffffffff811115614fbd575f80fd5b82016101008185031215612fdf575f80fd5b803562ffffff81168114614dfa575f80fd5b5f8060408385031215614ff2575f80fd5b8235614ffd81614ddb565b915061500b60208401614fcf565b90509250929050565b5f8060408385031215615025575f80fd5b823561503081614ddb565b946020939093013593505050565b8060020b8114610a32575f80fd5b8035614dfa8161503e565b5f805f805f60a0868803121561506b575f80fd5b853561507681614ddb565b945061508460208701614fcf565b9350604086013561509481614ddb565b925060608601356150a48161503e565b915060808601356150b481614ddb565b809150509295509295909350565b5f602082840312156150d2575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115612fce57612fce6150d9565b5f60208284031215615110575f80fd5b8151612fdf81614ddb565b81810381811115612fce57612fce6150d9565b805161ffff81168114614dfa575f80fd5b8015158114610a32575f80fd5b5f805f805f8060c08789031215615161575f80fd5b865161516c81614ddb565b602088015190965061517d8161503e565b945061518b6040880161512e565b93506151996060880161512e565b92506151a76080880161512e565b915060a08701516151b78161513f565b809150509295509295509295565b5f808335601e198436030181126151da575f80fd5b83018035915067ffffffffffffffff8211156151f4575f80fd5b6020019150600681901b3603821315614e6f575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f6040828403128015615230575f80fd5b506040805190810167ffffffffffffffff8111828210171561526057634e487b7160e01b5f52604160045260245ffd5b604052823581526020928301359281019290925250919050565b5f8235609e1983360301811261528e575f80fd5b9190910192915050565b5f602082840312156152a8575f80fd5b8135612fdf8161513f565b5f602082840312156152c3575f80fd5b815160ff81168114612fdf575f80fd5b5f808335601e198436030181126152e8575f80fd5b83018035915067ffffffffffffffff821115615302575f80fd5b602001915036819003821315614e6f575f80fd5b5f808335601e1984360301811261532b575f80fd5b83018035915067ffffffffffffffff821115615345575f80fd5b602001915061018081023603821315614e6f575f80fd5b8082028115828204841417612fce57612fce6150d9565b6001815b60018411156153ae57808504811115615392576153926150d9565b60018416156153a057908102905b60019390931c928002615377565b935093915050565b5f826153c457506001612fce565b816153d057505f612fce565b81600181146153e657600281146153f05761540c565b6001915050612fce565b60ff841115615401576154016150d9565b50506001821b612fce565b5060208310610133831016604e8410600b841016171561542f575081810a612fce565b61543b5f198484615373565b805f190482111561544e5761544e6150d9565b029392505050565b5f612fdf60ff8416836153b6565b5f60208284031215615474575f80fd5b8151612fdf8161513f565b5f8060408385031215615490575f80fd5b505080516020909101519092909150565b62ffffff8281168282160390811115612fce57612fce6150d9565b80516001600160801b0381168114614dfa575f80fd5b5f805f606084860312156154e4575f80fd5b6154ed846154bc565b602085015160409095015190969495509392505050565b5f60208284031215615514575f80fd5b8151612fdf8161503e565b5f6020828403121561552f575f80fd5b8135612fdf8161503e565b61018081016155598261554c85614def565b6001600160a01b03169052565b61556560208401614def565b6001600160a01b0316602083015261557f6040840161504c565b61558e604084018260020b9052565b5061559b6060840161504c565b6155aa606084018260020b9052565b506155b76080840161504c565b6155c6608084018260020b9052565b5060a0838101359083015260c0808401359083015260e0808401359083015261010080840135908301526155fd6101208401614def565b6001600160a01b031661012083015261014083810135908301526156246101608401614def565b6001600160a01b038116610160840152614c72565b5f805f806080858703121561564c575f80fd5b8451935061565c602086016154bc565b6040860151606090960151949790965092505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f82518060208501845e5f920191825250919050565b5f805f805f805f80610100898b0312156156eb575f80fd5b88516bffffffffffffffffffffffff81168114615706575f80fd5b60208a015190985061571781614ddb565b60408a015190975061572881614ddb565b60608a015190965061573981614ddb565b60808a015190955061574a8161503e565b60a08a015190945061575b8161503e565b60c08a015190935061576c8161503e565b915061577a60e08a016154bc565b90509295985092959890939650565b5f600160ff1b820161579d5761579d6150d9565b505f0390565b5f8160020b627fffff1981036157bb576157bb6150d9565b5f0392915050565b634e487b7160e01b5f52601260045260245ffd5b5f826157e5576157e56157c3565b500490565b5f826157f8576157f86157c3565b500690565b6001600160a01b038281168282160390811115612fce57612fce6150d9565b634e487b7160e01b5f52603160045260245ffd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe000000000000000000000000940181a94a35a4569e4529a3cdfb74e38fd98631416464726573733a206c6f772d6c6576656c207374617469632063616c6c206661696c6564a264697066735822122078c84312c5a9d8d3bfd7e90095a8fbf07e8c3a3f1ea7ffe4084818da201d3bb164736f6c634300081a0033000000000000000000000000827922686190790b37229fd06084350e74485b720000000000000000000000005e7bb104d84c7cb9b682aac2f3d509f5f406809a00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a50000000000000000000000006f441151b478e0d60588f221f1a35bcc3f7ab981
Deployed Bytecode
0x60806040526004361061021d575f3560e01c80637ecd67171161011e578063c45a0155116100a8578063dce4312b1161006d578063dce4312b1461065e578063e0be9cfd1461067d578063ef5cfb8c14610692578063f3fef3a3146106b1578063f96ac622146106d0575f80fd5b8063c45a0155146105c6578063c6b29347146105f9578063c70920bc1461060c578063d21220a714610620578063d677d8681461063f575f80fd5b8063a6f19c84116100ee578063a6f19c8414610523578063a9a36dcd14610542578063acecf6f514610556578063af640d0f14610575578063c40394d3146105a8575f80fd5b80637ecd67171461048457806384397888146104ad5780638456cb59146104e05780638c04166f146104f4575f80fd5b8063426a8493116101aa5780635c975abb1161016f5780635c975abb146103e4578063714cff5614610406578063718da7ee1461042757806378df8e70146104465780637dc0d1d014610465575f80fd5b8063426a84931461035f57806342fb9d4414610221578063452a93201461037e57806346c96aac146103925780635933599a146103c5575f80fd5b80630e2e9b0f116101f05780630e2e9b0f146102a2578063150b7a02146102c85780631691bd6f1461030c57806316f0115b1461032c5780633f4ba83a1461034b575f80fd5b8063065756db1461022157806308c6ef08146102425780630af6ce85146102565780630dfe16811461026b575b5f80fd5b34801561022c575f80fd5b505f5b6040519081526020015b60405180910390f35b34801561024d575f80fd5b5061022f6106ef565b610269610264366004614dff565b610845565b005b348015610276575f80fd5b5060985461028a906001600160a01b031681565b6040516001600160a01b039091168152602001610239565b3480156102ad575f80fd5b50609c5461028a90630100000090046001600160a01b031681565b3480156102d3575f80fd5b506102f36102e2366004614e76565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610239565b348015610317575f80fd5b5061028a5f8051602061586683398151915281565b348015610337575f80fd5b50609d5461028a906001600160a01b031681565b348015610356575f80fd5b50610269610976565b34801561036a575f80fd5b50610269610379366004614dff565b610a35565b348015610389575f80fd5b5061028a610b6c565b34801561039d575f80fd5b5061028a7f00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a581565b3480156103d0575f80fd5b506102696103df366004614ee4565b610bf2565b3480156103ef575f80fd5b5060335460ff166040519015158152602001610239565b348015610411575f80fd5b5061041a610d37565b6040516102399190614efb565b348015610432575f80fd5b50610269610441366004614f3d565b610d43565b348015610451575f80fd5b5060975461028a906001600160a01b031681565b348015610470575f80fd5b50609a5461028a906001600160a01b031681565b34801561048f575f80fd5b50610498610f14565b60408051928352602083019190915201610239565b3480156104b8575f80fd5b5061028a7f000000000000000000000000827922686190790b37229fd06084350e74485b7281565b3480156104eb575f80fd5b50610269610f34565b3480156104ff575f80fd5b50609c5461050f9062ffffff1681565b60405162ffffff9091168152602001610239565b34801561052e575f80fd5b50609e5461028a906001600160a01b031681565b34801561054d575f80fd5b50610269610ff0565b348015610561575f80fd5b50610498610570366004614f3d565b611225565b348015610580575f80fd5b5061022f7f491defc0794897991a8e5e9fa49dcbed24fe84ee079750b1db3f4df77fb17cb581565b3480156105b3575f80fd5b506102696105c2366004614f58565b5050565b3480156105d1575f80fd5b5061028a7f0000000000000000000000005e7bb104d84c7cb9b682aac2f3d509f5f406809a81565b348015610604575f80fd5b505f80610498565b348015610617575f80fd5b5061049861136d565b34801561062b575f80fd5b5060995461028a906001600160a01b031681565b34801561064a575f80fd5b50610269610659366004614f97565b611531565b348015610669575f80fd5b50610269610678366004614fe1565b61208e565b348015610688575f80fd5b5061022f609b5481565b34801561069d575f80fd5b506102696106ac366004614f3d565b61234d565b3480156106bc575f80fd5b506104986106cb366004615014565b6126c3565b3480156106db575f80fd5b506102696106ea366004615057565b612a16565b5f805f6106fc609f612fc5565b609e549091506001600160a01b03165f5b8281101561081a575f610721609f83612fd4565b604051637980d7a160e11b8152600481018290529091506001600160a01b0384169063f301af4290602401602060405180830381865afa158015610767573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061078b91906150c2565b61079590866150ed565b604051633e491d4760e01b8152306004820152602481018390529095506001600160a01b03841690633e491d4790604401602060405180830381865afa1580156107e1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061080591906150c2565b61080f90866150ed565b94505060010161070d565b5061083083609b54620f424062ffffff16612fe6565b60a15461083d91906150ed565b935050505090565b61084d61308b565b6097546001600160a01b031633811461088f57604051635fc5149960e11b81523360048201526001600160a01b03821660248201526044015b60405180910390fd5b6108976130e4565b34156108b6576040516390eed9e960e01b815260040160405180910390fd5b821580156108c2575081155b156108e0576040516378b7ac0360e01b815260040160405180910390fd5b82156108fe576098546108fe906001600160a01b031685308661312a565b811561091c5760995461091c906001600160a01b031685308561312a565b604080516001600160a01b0386168152602081018590529081018390527fb6b61f73303cc86cb9e6eee7756d1334f129e7711d778aa201fb3fa611dfe6dd9060600160405180910390a1506109716001606555565b505050565b61097e6131a2565b5f7f0000000000000000000000006f441151b478e0d60588f221f1a35bcc3f7ab9816001600160a01b0316639fd0506d6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109ff9190615100565b90506001600160a01b0381163314610a2a57604051636570ecab60e11b815260040160405180910390fd5b610a326131eb565b50565b610a3d61308b565b610a456130e4565b60975f9054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a95573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ab99190615100565b6001600160a01b0316336001600160a01b031614610aea5760405163f68ef6bf60e01b815260040160405180910390fd5b6098546099546001600160a01b039182169116610b0882868661323d565b610b1c6001600160a01b038216868561323d565b60408051858152602081018590526001600160a01b038716917f300cfe37bf342ac8761414ef964d4a4d284b045e489703c08c85b9d1ea64801c910160405180910390a250506109716001606555565b5f7f0000000000000000000000006f441151b478e0d60588f221f1a35bcc3f7ab9816001600160a01b0316639fd0506d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bc9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bed9190615100565b905090565b6097546040805163481c6a7560e01b815290515f926001600160a01b03169163481c6a759160048083019260209291908290030181865afa158015610c39573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5d9190615100565b90506001600160a01b0381163314610c995760405163167231b360e21b81523360048201526001600160a01b0382166024820152604401610886565b610ca16130e4565b609b54828103610cc45760405163142842f960e11b815260040160405180910390fd5b620f4240831115610ceb576040516335f24c0760e01b815260048101849052602401610886565b610cf3610ff0565b609b83905560408051828152602081018590527f5b5a6a8527892eb1e879279ea1addd664eef55099889d3fe13e926a5fd7c360591015b60405180910390a1505050565b6060610bed609f6132cb565b610d4b6130e4565b6097546040805163481c6a7560e01b815290515f926001600160a01b03169163481c6a759160048083019260209291908290030181865afa158015610d92573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610db69190615100565b9050336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dfe573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e229190615100565b6001600160a01b031614610e4957604051630fc9f84560e11b815260040160405180910390fd5b609c546001600160a01b0363010000009091048116908316610e7e57604051639fabe1c160e01b815260040160405180910390fd5b826001600160a01b0316816001600160a01b031603610eb05760405163fb1dbe5560e01b815260040160405180910390fd5b609c80546301000000600160b81b03191663010000006001600160a01b038681169182029290921790925560408051918416825260208201929092527f80f0c3fe8b42050f13c290b2651f6499bda92e8864245df1c14f1604851d61809101610d2a565b5f80610f1e61308b565b610f266130e4565b610f306001606555565b9091565b610f3c6130e4565b5f7f0000000000000000000000006f441151b478e0d60588f221f1a35bcc3f7ab9816001600160a01b0316639fd0506d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f99573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fbd9190615100565b90506001600160a01b0381163314610fe857604051636570ecab60e11b815260040160405180910390fd5b610a326132d7565b610ff861308b565b6110006130e4565b5f61100b609f612fc5565b609e546040516370a0823160e01b81523060048201529192506001600160a01b0316905f905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015611063573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061108791906150c2565b90505f5b83811015611103575f61109f609f83612fd4565b604051631c4b774b60e01b8152600481018290529091506001600160a01b03851690631c4b774b906024015f604051808303815f87803b1580156110e1575f80fd5b505af11580156110f3573d5f803e3d5ffd5b505050506001820191505061108b565b506040516370a0823160e01b815230600482015281905f80516020615866833981519152906370a0823190602401602060405180830381865afa15801561114c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061117091906150c2565b61117a919061511b565b90505f61119282609b54620f424062ffffff16612fe6565b60a15461119f91906150ed565b5f60a155609c54909150630100000090046001600160a01b03166111d15f805160206158668339815191528284613314565b806001600160a01b03167fb394755410f704d048c51b075262ff71c1049c4a7c48025fc2ccd15d23d5b6778360405161120c91815260200190565b60405180910390a250505050506112236001606555565b565b5f805f611232609f612fc5565b90505f5b8181101561127b575f8061125461124e609f85612fd4565b88613344565b909250905061126382876150ed565b955061126f81866150ed565b94505050600101611236565b506098546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156112c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112e691906150c2565b6112f090846150ed565b6099546040516370a0823160e01b81523060048201529194506001600160a01b0316906370a0823190602401602060405180830381865afa158015611337573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061135b91906150c2565b61136590836150ed565b915050915091565b5f805f61137a609f612fc5565b90505f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa1580156113cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113f1919061514c565b505050505090505f5b8281101561143f575f80611418611412609f85612fd4565b85613344565b909250905061142782886150ed565b965061143381876150ed565b955050506001016113fa565b506098546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015611486573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114aa91906150c2565b6114b490856150ed565b6099546040516370a0823160e01b81523060048201529195506001600160a01b0316906370a0823190602401602060405180830381865afa1580156114fb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061151f91906150c2565b61152990846150ed565b925050509091565b61153961308b565b6115416130e4565b6097546040805163481c6a7560e01b815290515f926001600160a01b03169163481c6a759160048083019260209291908290030181865afa158015611588573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115ac9190615100565b90506001600160a01b03811633146115e85760405163167231b360e21b81523360048201526001600160a01b0382166024820152604401610886565b5f6115f383806151c5565b905090505f805f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa15801561164a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061166e919061514c565b505050505090505f8411156117bd57609b545f90815b8681101561174c576116ba6116998a806151c5565b838181106116a9576116a961520b565b609f92604090910201359050613382565b6116d757604051637ec8def360e11b815260040160405180910390fd5b5f80806117136116e78d806151c5565b868181106116f7576116f761520b565b90506040020180360381019061170d919061521f565b88613399565b91945092509050611724838a6150ed565b985061173082896150ed565b975061173c81876150ed565b9550600184019350505050611684565b5061175b8282620f4240612fe6565b60a15f82825461176b91906150ed565b9091555050608088013585101561179557604051632b0bd3a160e21b815260040160405180910390fd5b8760a001358410156117ba57604051630d517e6760e01b815260040160405180910390fd5b50505b5f6117cb604088018861527a565b604001351115611de9576098546099546001600160a01b0391821691166118f06117f860408a018a61527a565b6118099060a0810190608001615298565b61181660408b018b61527a565b6060013561182760408c018c61527a565b60400135856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611867573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061188b91906152b3565b856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118eb91906152b3565b613722565b5f6118fe60408a018a61527a565b61190f9060a0810190608001615298565b156119c45761195761192460408b018b61527a565b611935906040810190602001614f3d565b61194260408c018c61527a565b6001600160a01b03861691906040013561323d565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611999573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119bd91906150c2565b9050611a70565b611a076119d460408b018b61527a565b6119e5906040810190602001614f3d565b6119f260408c018c61527a565b6001600160a01b03851691906040013561323d565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611a49573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a6d91906150c2565b90505b6097546001600160a01b0316611a8960408b018b61527a565b611a9a906040810190602001614f3d565b6001600160a01b03161480611afd57506001600160a01b037f000000000000000000000000827922686190790b37229fd06084350e74485b7216611ae160408b018b61527a565b611af2906040810190602001614f3d565b6001600160a01b0316145b80611b385750609e546001600160a01b0316611b1c60408b018b61527a565b611b2d906040810190602001614f3d565b6001600160a01b0316145b80611b7557505f80516020615866833981519152611b5960408b018b61527a565b611b6a906040810190602001614f3d565b6001600160a01b0316145b15611b93576040516364ec5f9b60e01b815260040160405180910390fd5b611c0e611ba360408b018b61527a565b611bad90806152d3565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611bee9250505060408c018c61527a565b611bff906040810190602001614f3d565b6001600160a01b03169061386f565b50611c1c60408a018a61527a565b611c2d9060a0810190608001615298565b15611d0e576040516370a0823160e01b815230600482015281906001600160a01b038416906370a0823190602401602060405180830381865afa158015611c76573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c9a91906150c2565b611ca4919061511b565b905080611cb460408b018b61527a565b606001351115611cd75760405163428637bb60e11b815260040160405180910390fd5b611d09611ce760408b018b61527a565b611cf8906040810190602001614f3d565b6001600160a01b038516905f61323d565b611de5565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015611d52573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d7691906150c2565b611d80919061511b565b905080611d9060408b018b61527a565b606001351115611db35760405163428637bb60e11b815260040160405180910390fd5b611de5611dc360408b018b61527a565b611dd4906040810190602001614f3d565b6001600160a01b038416905f61323d565b5050505b5f80609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa158015611e3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e5f919061514c565b50939650611e769350505060208a019050896151c5565b9650508515611f5d57609b545f90815b88811015611f3657611e9e61169960208d018d6151c5565b611ebb57604051637ec8def360e11b815260040160405180910390fd5b5f805f611efd8e8060200190611ed191906151c5565b86818110611ee157611ee161520b565b905060400201803603810190611ef7919061521f565b8a6138b2565b91945092509050611f0e83896150ed565b9750611f1a82886150ed565b9650611f2681876150ed565b9550600184019350505050611e86565b50611f458282620f4240612fe6565b60a15f828254611f5591906150ed565b909155505050505b611f6a6060890189615316565b9650508515612035576098546099546001600160a01b0391821691165f5b88811015611fe7575f80611fc0611fa260608f018f615316565b85818110611fb257611fb261520b565b905061018002018686613c24565b9092509050611fcf82886150ed565b9650611fdb81876150ed565b95505050600101611f88565b508960c0013584101561200d5760405163ed8bd62d60e01b815260040160405180910390fd5b8960e00135831015612032576040516342a96c6d60e11b815260040160405180910390fd5b50505b6040805186815260208101869052908101839052606081018290527f297b58c128b54f4e5041ecc8d817795f247871ea6cb93bd6f8d1db646d1b47249060800160405180910390a150505050505050610a326001606555565b6098546099546040805163313ce56760e01b815290516001600160a01b0393841693909216915f91849163313ce567916004808201926020929091908290030181865afa1580156120e1573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210591906152b3565b90505f826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612144573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061216891906152b3565b90505f866001600160a01b031663e84b8fe56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156121a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121cb91906150c2565b90505f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa15801561221e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612242919061514c565b505050505090505f6001600160801b038016826001600160a01b0316116122955761228e6122796001600160a01b0384168061535c565b61228487600a615456565b600160c01b612fe6565b90506122cd565b6122ca6122b56001600160a01b0384168068010000000000000000612fe6565b6122c087600a615456565b600160801b612fe6565b90505b5f6123196123058584116122ea576122e5848761511b565b6122f4565b6122f4868561511b565b6122ff88600a615456565b85612fe6565b620f424061231488600a615456565b612fe6565b90508862ffffff168111156123415760405163371446a760e21b815260040160405180910390fd5b50505050505050505050565b60975f9054906101000a90046001600160a01b03166001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561239d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c19190615100565b6001600160a01b0316336001600160a01b0316146123f25760405163f68ef6bf60e01b815260040160405180910390fd5b6123fa61308b565b6124026130e4565b6001600160a01b03811661242957604051639fabe1c160e01b815260040160405180910390fd5b5f612434609f612fc5565b609e546040516370a0823160e01b81523060048201529192505f916001600160a01b039091169082905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015612490573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124b491906150c2565b90505f5b84811015612530575f6124cc609f83612fd4565b604051631c4b774b60e01b8152600481018290529091506001600160a01b03851690631c4b774b906024015f604051808303815f87803b15801561250e575f80fd5b505af1158015612520573d5f803e3d5ffd5b50505050600182019150506124b8565b506040516370a0823160e01b815230600482015281905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015612579573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061259d91906150c2565b6125a7919061511b565b6125b190846150ed565b92506125c883609b54620f424062ffffff16612fe6565b60a15f8282546125d891906150ed565b909155505060a1546040516370a0823160e01b81523060048201525f91905f80516020615866833981519152906370a0823190602401602060405180830381865afa158015612629573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061264d91906150c2565b612657919061511b565b90506126715f805160206158668339815191528783613314565b856001600160a01b03167ffce6d5860f911bc27ece1365300332d2ddbe20c1adc46ee2eddd8f72c48053b2826040516126ac91815260200190565b60405180910390a25050505050610a326001606555565b6097545f9081906001600160a01b031633811461270457604051635fc5149960e11b81523360048201526001600160a01b0382166024820152604401610886565b61270c61308b565b6001600160a01b03851661273357604051639fabe1c160e01b815260040160405180910390fd5b835f03612753576040516398c5be9760e01b815260040160405180910390fd5b670de0b6b3a764000084111561277c57604051632139c5c160e01b815260040160405180910390fd5b5f612787609f6132cb565b6098546099546040516370a0823160e01b81523060048201529293505f926001600160a01b0392831692909116906128139083906370a08231906024015b602060405180830381865afa1580156127e0573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061280491906150c2565b89670de0b6b3a7640000612fe6565b6040516370a0823160e01b8152306004820152909750612846906001600160a01b038316906370a08231906024016127c5565b95505f609d5f9054906101000a90046001600160a01b03166001600160a01b0316633850c7bd6040518163ffffffff1660e01b815260040160c060405180830381865afa158015612899573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128bd919061514c565b505050505090506128df60405180604001604052805f81526020015f81525090565b602081018a90525f5b8651811015612956578681815181106129035761290361520b565b602090810291909101015182525f808061291d8587613399565b9194509250905061292e838e6150ed565b9c5061293a828d6150ed565b9b50612946818a6150ed565b98506001840193505050506128e8565b50609b546129688682620f4240612fe6565b60a15f82825461297891906150ed565b90915550508915612997576129976001600160a01b0386168d8c613314565b88156129b1576129b16001600160a01b0385168d8b613314565b604080518c8152602081018c90529081018a90526001600160a01b038d16907f9744d0a120f7c7d7906cfe3c05b50669fb49aa6d778b099d5d6edc386dee5b599060600160405180910390a250505050505050612a0e6001606555565b509250929050565b5f54610100900460ff1615808015612a3457505f54600160ff909116105b80612a4d5750303b158015612a4d57505f5460ff166001145b612ab05760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610886565b5f805460ff191660011790558015612ad1575f805461ff0019166101001790555b6001600160a01b0382161580612aee57506001600160a01b038616155b80612b0057506001600160a01b038416155b15612b1e57604051639fabe1c160e01b815260040160405180910390fd5b620186a062ffffff86161115612b475760405163198a0acd60e31b815260040160405180910390fd5b609780546001600160a01b038085166001600160a01b03199283168117909355609a80548a8316931692909217909155609c80549187166301000000026001600160b81b031990921662ffffff89161791909117905560408051630dfe168160e01b815290515f9291630dfe16819160048083019260209291908290030181865afa158015612bd8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612bfc9190615100565b90505f836001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c5f9190615100565b90506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1480612ca857506001600160a01b03811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee145b15612cc6576040516390eed9e960e01b815260040160405180910390fd5b6001600160a01b0382165f805160206158668339815191521480612cff57506001600160a01b0381165f80516020615866833981519152145b15612d1d57604051631887580f60e21b815260040160405180910390fd5b6040516328af8d0b60e01b81526001600160a01b0383811660048301528281166024830152600287900b60448301525f917f0000000000000000000000005e7bb104d84c7cb9b682aac2f3d509f5f406809a909116906328af8d0b90606401602060405180830381865afa158015612d97573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612dbb9190615100565b90506001600160a01b038116612de4576040516301dbb3ff60e61b815260040160405180910390fd5b60405163b9a09fd560e01b81526001600160a01b0382811660048301525f917f00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a59091169063b9a09fd590602401602060405180830381865afa158015612e4c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612e709190615100565b604051631703e5f960e01b81526001600160a01b0380831660048301529192507f00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a590911690631703e5f990602401602060405180830381865afa158015612ed9573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612efd9190615464565b612f1a5760405163039b284d60e31b815260040160405180910390fd5b609d80546001600160a01b038085166001600160a01b031992831617909255609e8054848416908316179055609880548784169083161790556099805492861692909116919091179055612f6c613fcd565b612f74613ffb565b505050508015612fbd575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b505050505050565b5f612fce825490565b92915050565b5f612fdf8383614029565b9392505050565b5f80805f19858709858702925082811083820303915050805f0361301a575f841161300f575f80fd5b508290049050612fdf565b808411613025575f80fd5b5f84868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203025f889003889004909101858311909403939093029303949094049190911702949350505050565b6002606554036130dd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610886565b6002606555565b60335460ff16156112235760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610886565b6040516001600160a01b03808516602483015283166044820152606481018290526131959085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261404f565b50505050565b6001606555565b60335460ff166112235760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610886565b6131f36131a2565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261328e8482614122565b613195576040516001600160a01b03841660248201525f60448201526132c190859063095ea7b360e01b9060640161315e565b613195848261404f565b60605f612fdf836141c3565b6132df6130e4565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586132203390565b6040516001600160a01b03831660248201526044810182905261097190849063a9059cbb60e01b9060640161315e565b5f805f805f6133528761421c565b92509250925061337486613365856142cd565b61336e856142cd565b846146e6565b909890975095505050505050565b5f8181526001830160205260408120541515612fdf565b5f805f805f806133ab885f0151614781565b909450925090506133bc81856150ed565b9350506133e76133e2826001600160801b03168960200151670de0b6b3a7640000612fe6565b6148f0565b6040805160a081018252895181526001600160801b03838116602083019081525f838501818152606085019182525f19608086019081529551630624e65f60e11b815285516004820152925190931660248301529151604482015290516064820152915160848301529192507f000000000000000000000000827922686190790b37229fd06084350e74485b726001600160a01b031690630c49ccbe9060a40160408051808303815f875af11580156134a2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906134c6919061547f565b5050604080516080810182528951815230602082019081526001600160801b0382840181815260608401828152945163fc6f786560e01b81529351600485015291516001600160a01b039081166024850152915181166044840152925190921660648201527f000000000000000000000000827922686190790b37229fd06084350e74485b72909116915063fc6f78659060840160408051808303815f875af1158015613575573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613599919061547f565b60208901519196509450670de0b6b3a763ffff190161363e578651604051630852cd8d60e31b815260048101919091527f000000000000000000000000827922686190790b37229fd06084350e74485b726001600160a01b0316906342966c68906024015f604051808303815f87803b158015613614575f80fd5b505af1158015613626573d5f803e3d5ffd5b505088516136389250609f915061495c565b50613719565b865160405163095ea7b360e01b81526001600160a01b03848116600483015260248201929092527f000000000000000000000000827922686190790b37229fd06084350e74485b729091169063095ea7b3906044015f604051808303815f87803b1580156136aa575f80fd5b505af11580156136bc573d5f803e3d5ffd5b5050885160405163b6b55f2560e01b815260048101919091526001600160a01b038516925063b6b55f2591506024015f604051808303815f87803b158015613702575f80fd5b505af1158015613714573d5f803e3d5ffd5b505050505b50509250925092565b84156137f157609a546040805163e84b8fe560e01b815290516137b8926001600160a01b03169163e84b8fe59160048083019260209291908290030181865afa158015613771573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061379591906150c2565b609c546137aa9062ffffff16620f42406154a1565b62ffffff16620f4240612fe6565b6137cd856137c785600a615456565b86612fe6565b10156137ec57604051634e7ce55560e01b815260040160405180910390fd5b613868565b609a546040805163a941ada960e01b8152905161383a926001600160a01b03169163a941ada99160048083019260209291908290030181865afa158015613771573d5f803e3d5ffd5b613849856137c784600a615456565b101561386857604051634e7ce55560e01b815260040160405180910390fd5b5050505050565b6060612fdf83835f6040518060400160405280601e81526020017f416464726573733a206c6f772d6c6576656c2063616c6c206661696c65640000815250614967565b5f805f805f6138c4875f015187613344565b885191935091505f9081906138d890614781565b50925090506138e781866150ed565b9450506139046133e2848a60200151670de0b6b3a7640000612fe6565b6001600160801b031692506139296133e2838a60200151670de0b6b3a7640000612fe6565b6040805160c0810182528a518152602081018690526001600160801b03929092169082018190525f6060830181905260808301525f1960a08301526098546099549194506001600160a01b03908116911685156139bb5760208301516139bb906001600160a01b038416907f000000000000000000000000827922686190790b37229fd06084350e74485b729061323d565b604083015115613a00576040830151613a00906001600160a01b038316907f000000000000000000000000827922686190790b37229fd06084350e74485b729061323d565b6040805163219f5d1760e01b81528451600482015260208501516024820152908401516044820152606084015160648201526080840151608482015260a084015160a48201527f000000000000000000000000827922686190790b37229fd06084350e74485b726001600160a01b03169063219f5d179060c4016060604051808303815f875af1158015613a96573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613aba91906154d2565b6020860151919b509950159050613aff57613aff6001600160a01b0383167f000000000000000000000000827922686190790b37229fd06084350e74485b725f61323d565b604083015115613b3d57613b3d6001600160a01b0382167f000000000000000000000000827922686190790b37229fd06084350e74485b725f61323d565b5050885160405163095ea7b360e01b81526001600160a01b03848116600483015260248201929092527f000000000000000000000000827922686190790b37229fd06084350e74485b72909116915063095ea7b3906044015f604051808303815f87803b158015613bac575f80fd5b505af1158015613bbe573d5f803e3d5ffd5b5050895160405163b6b55f2560e01b815260048101919091526001600160a01b038416925063b6b55f2591506024015f604051808303815f87803b158015613c04575f80fd5b505af1158015613c16573d5f803e3d5ffd5b505050505050509250925092565b5f80806001600160a01b038516613c3e6020880188614f3d565b6001600160a01b031614613c6557604051633e2e391b60e11b815260040160405180910390fd5b6001600160a01b038416613c7f6040880160208901614f3d565b6001600160a01b031614613ca65760405163f593f01d60e01b815260040160405180910390fd5b609d54604080516334324e9f60e21b815290515f926001600160a01b03169163d0c93a7c9160048083019260209291908290030181865afa158015613ced573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d119190615504565b9050600281900b613d286060890160408a0161551f565b60020b14613d4957604051637166dcc160e01b815260040160405180910390fd5b60a087013515613d8b57613d8b6001600160a01b0387167f000000000000000000000000827922686190790b37229fd06084350e74485b7260a08a013561323d565b60c087013515613dcd57613dcd6001600160a01b0386167f000000000000000000000000827922686190790b37229fd06084350e74485b7260c08a013561323d565b60405163b5007d1f60e01b81526001600160a01b037f000000000000000000000000827922686190790b37229fd06084350e74485b72169063b5007d1f90613e19908a9060040161553a565b6080604051808303815f875af1158015613e35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e599190615639565b90965094509092505060a087013515613ea057613ea06001600160a01b0387167f000000000000000000000000827922686190790b37229fd06084350e74485b725f61323d565b60c087013515613ede57613ede6001600160a01b0386167f000000000000000000000000827922686190790b37229fd06084350e74485b725f61323d565b613ee9609f83614a3e565b50609e5460405163095ea7b360e01b81526001600160a01b039182166004820181905260248201859052917f000000000000000000000000827922686190790b37229fd06084350e74485b72169063095ea7b3906044015f604051808303815f87803b158015613f57575f80fd5b505af1158015613f69573d5f803e3d5ffd5b505060405163b6b55f2560e01b8152600481018690526001600160a01b038416925063b6b55f2591506024015f604051808303815f87803b158015613fac575f80fd5b505af1158015613fbe573d5f803e3d5ffd5b50505050505050935093915050565b5f54610100900460ff16613ff35760405162461bcd60e51b815260040161088690615672565b611223614a49565b5f54610100900460ff166140215760405162461bcd60e51b815260040161088690615672565b611223614a6f565b5f825f01828154811061403e5761403e61520b565b905f5260205f200154905092915050565b5f6140a3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614aa19092919063ffffffff16565b905080515f14806140c35750808060200190518101906140c39190615464565b6109715760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610886565b5f805f846001600160a01b03168460405161413d91906156bd565b5f604051808303815f865af19150503d805f8114614176576040519150601f19603f3d011682016040523d82523d5f602084013e61417b565b606091505b50915091508180156141a55750805115806141a55750808060200190518101906141a59190615464565b80156141ba57506001600160a01b0385163b15155b95945050505050565b6060815f0180548060200260200160405190810160405280929190818152602001828054801561421057602002820191905f5260205f20905b8154815260200190600101908083116141fc575b50505050509050919050565b5f805f806399fbab8860e01b8560405160240161423b91815260200190565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915290505f6142a36001600160a01b037f000000000000000000000000827922686190790b37229fd06084350e74485b721683614aaf565b9050808060200190518101906142b991906156d3565b919d909c50909a5098505050505050505050565b5f805f8360020b126142e2578260020b6142ef565b8260020b6142ef90615789565b90506142fe620d89e7196157a3565b60020b8111156143345760405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606401610886565b5f816001165f0361434957600160801b61435b565b6ffffcb933bd6fad37aa2d162d1a5940015b70ffffffffffffffffffffffffffffffffff169050600282161561439a576080614395826ffff97272373d413259a46990580e213a61535c565b901c90505b60048216156143c45760806143bf826ffff2e50f5f656932ef12357cf3c7fdcc61535c565b901c90505b60088216156143ee5760806143e9826fffe5caca7e10e4e61c3624eaa0941cd061535c565b901c90505b6010821615614418576080614413826fffcb9843d60f6159c9db58835c92664461535c565b901c90505b602082161561444257608061443d826fff973b41fa98c081472e6896dfb254c061535c565b901c90505b604082161561446c576080614467826fff2ea16466c96a3843ec78b326b5286161535c565b901c90505b6080821615614496576080614491826ffe5dee046a99a2a811c461f1969c305361535c565b901c90505b6101008216156144c15760806144bc826ffcbe86c7900a88aedcffc83b479aa3a461535c565b901c90505b6102008216156144ec5760806144e7826ff987a7253ac413176f2b074cf7815e5461535c565b901c90505b610400821615614517576080614512826ff3392b0822b70005940c7a398e4b70f361535c565b901c90505b61080082161561454257608061453d826fe7159475a2c29b7443b29c7fa6e889d961535c565b901c90505b61100082161561456d576080614568826fd097f3bdfd2022b8845ad8f792aa582561535c565b901c90505b612000821615614598576080614593826fa9f746462d870fdf8a65dc1f90e061e561535c565b901c90505b6140008216156145c35760806145be826f70d869a156d2a1b890bb3df62baf32f761535c565b901c90505b6180008216156145ee5760806145e9826f31be135f97d08fd981231505542fcfa661535c565b901c90505b6201000082161561461a576080614615826f09aa508b5b7a84e1c677de54f3e99bc961535c565b901c90505b62020000821615614645576080614640826e5d6af8dedb81196699c329225ee60461535c565b901c90505b6204000082161561466f57608061466a826d2216e584f5fa1ea926041bedfe9861535c565b901c90505b62080000821615614697576080614692826b048a170391f7dc42444e8fa261535c565b901c90505b5f8460020b13156146b0576146ad815f196157d7565b90505b6146bf640100000000826157ea565b156146cb5760016146cd565b5f5b6146de9060ff16602083901c6150ed565b949350505050565b5f80836001600160a01b0316856001600160a01b03161115614706579293925b846001600160a01b0316866001600160a01b0316116147315761472a858585614ad4565b9150614778565b836001600160a01b0316866001600160a01b0316101561476a57614756868585614ad4565b9150614763858785614b46565b9050614778565b614775858585614b46565b90505b94509492505050565b5f805f61478d8461421c565b609e546040516370a0823160e01b81523060048201526001600160a01b0390911695509093505f92505f8051602061586683398151915291506370a0823190602401602060405180830381865afa1580156147ea573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061480e91906150c2565b604051632e1a7d4d60e01b8152600481018790529091506001600160a01b03841690632e1a7d4d906024015f604051808303815f87803b158015614850575f80fd5b505af1158015614862573d5f803e3d5ffd5b50506040516370a0823160e01b81523060048201528392505f8051602061586683398151915291506370a0823190602401602060405180830381865afa1580156148ae573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906148d291906150c2565b6148dc919061511b565b6148e690856150ed565b9350509193909250565b5f6001600160801b038211156149585760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401610886565b5090565b5f612fdf8383614b8f565b6060824710156149c85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610886565b5f80866001600160a01b031685876040516149e391906156bd565b5f6040518083038185875af1925050503d805f8114614a1d576040519150601f19603f3d011682016040523d82523d5f602084013e614a22565b606091505b5091509150614a3387838387614c79565b979650505050505050565b5f612fdf8383614cf1565b5f54610100900460ff1661319b5760405162461bcd60e51b815260040161088690615672565b5f54610100900460ff16614a955760405162461bcd60e51b815260040161088690615672565b6033805460ff19169055565b60606146de84845f85614967565b6060612fdf838360405180606001604052806025815260200161588660259139614d3d565b5f826001600160a01b0316846001600160a01b03161115614af3579192915b6001600160a01b038416614b3c6fffffffffffffffffffffffffffffffff60601b606085901b16614b2487876157fd565b6001600160a01b0316866001600160a01b0316612fe6565b6146de91906157d7565b5f826001600160a01b0316846001600160a01b03161115614b65579192915b6146de6001600160801b038316614b7c86866157fd565b6001600160a01b0316600160601b612fe6565b5f8181526001830160205260408120548015614c69575f614bb160018361511b565b85549091505f90614bc49060019061511b565b9050818114614c23575f865f018281548110614be257614be261520b565b905f5260205f200154905080875f018481548110614c0257614c0261520b565b5f918252602080832090910192909255918252600188019052604090208390555b8554869080614c3457614c3461581c565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050612fce565b5f915050612fce565b5092915050565b60608315614ce75782515f03614ce0576001600160a01b0385163b614ce05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610886565b50816146de565b6146de8383614db1565b5f818152600183016020526040812054614d3657508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155612fce565b505f612fce565b60605f80856001600160a01b031685604051614d5991906156bd565b5f60405180830381855afa9150503d805f8114614d91576040519150601f19603f3d011682016040523d82523d5f602084013e614d96565b606091505b5091509150614da786838387614c79565b9695505050505050565b815115614dc15781518083602001fd5b8060405162461bcd60e51b81526004016108869190615830565b6001600160a01b0381168114610a32575f80fd5b8035614dfa81614ddb565b919050565b5f805f60608486031215614e11575f80fd5b8335614e1c81614ddb565b95602085013595506040909401359392505050565b5f8083601f840112614e41575f80fd5b50813567ffffffffffffffff811115614e58575f80fd5b602083019150836020828501011115614e6f575f80fd5b9250929050565b5f805f805f60808688031215614e8a575f80fd5b8535614e9581614ddb565b94506020860135614ea581614ddb565b935060408601359250606086013567ffffffffffffffff811115614ec7575f80fd5b614ed388828901614e31565b969995985093965092949392505050565b5f60208284031215614ef4575f80fd5b5035919050565b602080825282518282018190525f918401906040840190835b81811015614f32578351835260209384019390920191600101614f14565b509095945050505050565b5f60208284031215614f4d575f80fd5b8135612fdf81614ddb565b5f8060208385031215614f69575f80fd5b823567ffffffffffffffff811115614f7f575f80fd5b614f8b85828601614e31565b90969095509350505050565b5f60208284031215614fa7575f80fd5b813567ffffffffffffffff811115614fbd575f80fd5b82016101008185031215612fdf575f80fd5b803562ffffff81168114614dfa575f80fd5b5f8060408385031215614ff2575f80fd5b8235614ffd81614ddb565b915061500b60208401614fcf565b90509250929050565b5f8060408385031215615025575f80fd5b823561503081614ddb565b946020939093013593505050565b8060020b8114610a32575f80fd5b8035614dfa8161503e565b5f805f805f60a0868803121561506b575f80fd5b853561507681614ddb565b945061508460208701614fcf565b9350604086013561509481614ddb565b925060608601356150a48161503e565b915060808601356150b481614ddb565b809150509295509295909350565b5f602082840312156150d2575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b80820180821115612fce57612fce6150d9565b5f60208284031215615110575f80fd5b8151612fdf81614ddb565b81810381811115612fce57612fce6150d9565b805161ffff81168114614dfa575f80fd5b8015158114610a32575f80fd5b5f805f805f8060c08789031215615161575f80fd5b865161516c81614ddb565b602088015190965061517d8161503e565b945061518b6040880161512e565b93506151996060880161512e565b92506151a76080880161512e565b915060a08701516151b78161513f565b809150509295509295509295565b5f808335601e198436030181126151da575f80fd5b83018035915067ffffffffffffffff8211156151f4575f80fd5b6020019150600681901b3603821315614e6f575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f6040828403128015615230575f80fd5b506040805190810167ffffffffffffffff8111828210171561526057634e487b7160e01b5f52604160045260245ffd5b604052823581526020928301359281019290925250919050565b5f8235609e1983360301811261528e575f80fd5b9190910192915050565b5f602082840312156152a8575f80fd5b8135612fdf8161513f565b5f602082840312156152c3575f80fd5b815160ff81168114612fdf575f80fd5b5f808335601e198436030181126152e8575f80fd5b83018035915067ffffffffffffffff821115615302575f80fd5b602001915036819003821315614e6f575f80fd5b5f808335601e1984360301811261532b575f80fd5b83018035915067ffffffffffffffff821115615345575f80fd5b602001915061018081023603821315614e6f575f80fd5b8082028115828204841417612fce57612fce6150d9565b6001815b60018411156153ae57808504811115615392576153926150d9565b60018416156153a057908102905b60019390931c928002615377565b935093915050565b5f826153c457506001612fce565b816153d057505f612fce565b81600181146153e657600281146153f05761540c565b6001915050612fce565b60ff841115615401576154016150d9565b50506001821b612fce565b5060208310610133831016604e8410600b841016171561542f575081810a612fce565b61543b5f198484615373565b805f190482111561544e5761544e6150d9565b029392505050565b5f612fdf60ff8416836153b6565b5f60208284031215615474575f80fd5b8151612fdf8161513f565b5f8060408385031215615490575f80fd5b505080516020909101519092909150565b62ffffff8281168282160390811115612fce57612fce6150d9565b80516001600160801b0381168114614dfa575f80fd5b5f805f606084860312156154e4575f80fd5b6154ed846154bc565b602085015160409095015190969495509392505050565b5f60208284031215615514575f80fd5b8151612fdf8161503e565b5f6020828403121561552f575f80fd5b8135612fdf8161503e565b61018081016155598261554c85614def565b6001600160a01b03169052565b61556560208401614def565b6001600160a01b0316602083015261557f6040840161504c565b61558e604084018260020b9052565b5061559b6060840161504c565b6155aa606084018260020b9052565b506155b76080840161504c565b6155c6608084018260020b9052565b5060a0838101359083015260c0808401359083015260e0808401359083015261010080840135908301526155fd6101208401614def565b6001600160a01b031661012083015261014083810135908301526156246101608401614def565b6001600160a01b038116610160840152614c72565b5f805f806080858703121561564c575f80fd5b8451935061565c602086016154bc565b6040860151606090960151949790965092505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f82518060208501845e5f920191825250919050565b5f805f805f805f80610100898b0312156156eb575f80fd5b88516bffffffffffffffffffffffff81168114615706575f80fd5b60208a015190985061571781614ddb565b60408a015190975061572881614ddb565b60608a015190965061573981614ddb565b60808a015190955061574a8161503e565b60a08a015190945061575b8161503e565b60c08a015190935061576c8161503e565b915061577a60e08a016154bc565b90509295985092959890939650565b5f600160ff1b820161579d5761579d6150d9565b505f0390565b5f8160020b627fffff1981036157bb576157bb6150d9565b5f0392915050565b634e487b7160e01b5f52601260045260245ffd5b5f826157e5576157e56157c3565b500490565b5f826157f8576157f86157c3565b500690565b6001600160a01b038281168282160390811115612fce57612fce6150d9565b634e487b7160e01b5f52603160045260245ffd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f8301168401019150509291505056fe000000000000000000000000940181a94a35a4569e4529a3cdfb74e38fd98631416464726573733a206c6f772d6c6576656c207374617469632063616c6c206661696c6564a264697066735822122078c84312c5a9d8d3bfd7e90095a8fbf07e8c3a3f1ea7ffe4084818da201d3bb164736f6c634300081a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000827922686190790b37229fd06084350e74485b720000000000000000000000005e7bb104d84c7cb9b682aac2f3d509f5f406809a00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a50000000000000000000000006f441151b478e0d60588f221f1a35bcc3f7ab981
-----Decoded View---------------
Arg [0] : nftPositionManager_ (address): 0x827922686190790b37229fd06084350E74485b72
Arg [1] : factory_ (address): 0x5e7BB104d84c7CB9B682AaC2F3d509f5F406809A
Arg [2] : voter_ (address): 0x16613524e02ad97eDfeF371bC883F2F5d6C480A5
Arg [3] : guardian_ (address): 0x6F441151B478E0d60588f221f1A35BcC3f7aB981
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000827922686190790b37229fd06084350e74485b72
Arg [1] : 0000000000000000000000005e7bb104d84c7cb9b682aac2f3d509f5f406809a
Arg [2] : 00000000000000000000000016613524e02ad97edfef371bc883f2f5d6c480a5
Arg [3] : 0000000000000000000000006f441151b478e0d60588f221f1a35bcc3f7ab981
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 32 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.