Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
AirPuffHandlerM
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 1 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import "./interfaces/ILending.sol"; import "./interfaces/IAirPuffVaultM.sol"; import "./interfaces/AggregatorV3Interface.sol"; import "./interfaces/IAPI3Oracle.sol"; interface IVectorOracle { function consultvETHPrice() external view returns (uint256); } interface IWETH { function deposit() external payable; function withdraw(uint256) external; function decimals() external view returns (uint8); } interface IAsset { // The IAsset interface might not explicitly define methods // since it's used as a type marker in Balancer's system. // Actual interactions with assets (tokens) would use the standard ERC20 methods or equivalent. } interface ISwapRouter { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint deadline; uint amountIn; uint amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps amountIn of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as ExactInputSingleParams in calldata /// @return amountOut The amount of the received token function exactInputSingle( ExactInputSingleParams calldata params ) external payable returns (uint amountOut); struct ExactInputParams { bytes path; address recipient; uint deadline; uint amountIn; uint amountOutMinimum; } /// @notice Swaps amountIn of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as ExactInputParams in calldata /// @return amountOut The amount of the received token function exactInput( ExactInputParams calldata params ) external payable returns (uint amountOut); } interface IBalancerVault { function batchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IAsset[] memory assets, FundManagement memory funds, int256[] memory limits, uint256 deadline ) external returns (int256[] memory assetDeltas); struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } enum SwapKind { GIVEN_IN, GIVEN_OUT } struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } } interface ICurveStableSwapNG { function exchange( int128 i, int128 j, uint256 dx, uint256 min_dy, address _receiver ) external returns (uint256); function coins(uint256 i) external view returns (address); } interface ICurveRouter { function exchange( address[11] memory _route, uint256[5][5] memory _swap_params, uint256 _amount, uint256 _expected, address[5] memory _pools ) external returns (uint256); } contract AirPuffHandlerM is OwnableUpgradeable, ReentrancyGuardUpgradeable, PausableUpgradeable { using SafeERC20Upgradeable for IERC20Upgradeable; using MathUpgradeable for uint256; using MathUpgradeable for uint128; address public keeper; bytes32 public balancerLRTAssetPool; bytes32 public balancerMixedLRTPool; address public LRTAsset; uint24 public uniFee; uint256 public balancerDeadline; struct SwapHandlerAddresses { address BalancerVault; address WETH; address Univ3Router; } struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } struct InterestRateConfig { uint256 CEIL_SLOPE_1; uint256 CEIL_SLOPE_2; uint256 MAX_INTEREST_SLOPE_1; uint256 MAX_INTEREST_SLOPE_2; uint256 baseInterestRate; } struct RateSnapshot { uint256 rate; uint256 timestamp; uint256 snapshotID; uint256 closeTimestamp; } struct CurvePools { address[5] curvePoolsIn; address[5] curvePoolsOut; } struct CurvePoolsSwapPaths { uint256[5][5] swapPathsIn; uint256[5][5] swapPathsOut; } struct CurveRouterSwapPath { address[11] routeIn; address[11] routeOut; } SwapHandlerAddresses public swapHandlerAddresses; InterestRateConfig public interestRateConfig; mapping(address => bool) public allowedVaults; mapping(address => address) public chainlinkOracle; mapping(address => mapping(uint256 => RateSnapshot)) public rateSnapshots; mapping(address => uint256) public vaultCurrentSnapshotID; mapping(address => address) public StrategyToLRT; uint256[50] private __gaps; mapping(address => address) public StrategyToCurvePool; mapping(address => bytes32) public balancerInPoolID; mapping(address => bytes32) public balancerOutPoolID; mapping(address => CurveRouterSwapPath) internal curveRouterSwapPath; mapping(address => CurvePools) internal curvePools; mapping(address => CurvePoolsSwapPaths) internal curvePoolsSwapPaths; mapping(address => bool) public strategyIsRouterPath; address public CurveRouter; uint256 public uniswapSlippage; address public UniswapQuoter; address public VectorOracle; mapping(address => bool) public isVectorStrategy; event HandlerAddressesChanged(address _Kyber); event RequestFulfilled(address indexed user, uint256 openAmount, uint256 closedAmount); event InterestParamsChanged(uint256 ceilSlope1, uint256 ceilSlope2, uint256 maxInterestSlope1, uint256 maxInterestSlope2, uint256 baseInterestRate); event ChainlinkOracleSet(address token, address oracle); event SnapshotTaken(); event SetKeeper(address indexed keeper); event PoolIDSet(bytes32 balancerLRTAssetPool, bytes32 balancerMixedLRTPool); event VaultToLRTAssetSet(address indexed strategy, address indexed LRTAsset); event UniFeeChanged(uint24 uniFee); event BalancerDeadlineSet(uint256 balancerDeadline); event StrategyToCurvePoolSet(address indexed strategy, address indexed curvePool); event StrategyToCurvePoolsInSet( address indexed strategy, address[5] curvePoolIn, address[5] curvePoolOut ); event CurveRouterSet(address indexed CurveRouter); event StrategyRouterSet(address indexed strategy, address[11] routerSwapPathIn, address[11] routerSwapPathOut); event SwapPathSet(address indexed strategy, uint256[5][5] swappathIn, uint256[5][5] swappathOut); event UniswapSlippageSet(uint256 slippage); modifier onlyKeeper() { require(msg.sender == keeper, "Only Keeper"); _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } function initialize() external initializer { interestRateConfig.baseInterestRate = 5e16; interestRateConfig.CEIL_SLOPE_1 = 8e17; interestRateConfig.CEIL_SLOPE_2 = 1e18; interestRateConfig.MAX_INTEREST_SLOPE_1 = 1e17; interestRateConfig.MAX_INTEREST_SLOPE_2 = 3e17; uniFee = 500; __Ownable_init(); __Pausable_init(); __ReentrancyGuard_init(); } function setIsVectorStrategy(address _strategy,bool _isVector) external onlyOwner { isVectorStrategy[_strategy] = _isVector; } function setVectorOracle(address _VectorOracle) external onlyOwner { require(_VectorOracle != address(0), "Zero address"); VectorOracle = _VectorOracle; } // -- Setters --// //10 for 1% slippage function setUniswapSlippage(uint256 _slippage) external onlyOwner { // max 10% slippage require(_slippage <= 100, "Invalid slippage"); uniswapSlippage = _slippage; emit UniswapSlippageSet(_slippage); } function setStrategyToCurvePool(address _strategy, address _curvePool) external onlyOwner { StrategyToCurvePool[_strategy] = _curvePool; emit StrategyToCurvePoolSet(_strategy, _curvePool); } function setBalancerDeadline(uint256 _balancerDeadline) external onlyOwner { balancerDeadline = _balancerDeadline; emit BalancerDeadlineSet(_balancerDeadline); } function setUniFee(uint24 _uniFee) external onlyOwner { uniFee = _uniFee; emit UniFeeChanged(_uniFee); } function setVaultToLRT(address _strategy, address _LRT) public onlyOwner { StrategyToLRT[_strategy] = _LRT; emit VaultToLRTAssetSet(_strategy, _LRT); } function setStrategyPoolID(bytes32 _balancerPoolIn, bytes32 _balancerPoolOut, address _strategy) public onlyOwner { balancerInPoolID[_strategy] = _balancerPoolIn; balancerOutPoolID[_strategy] = _balancerPoolOut; emit PoolIDSet(_balancerPoolIn, _balancerPoolOut); } function setKeeper(address _keeper) public onlyOwner { require(_keeper != address(0), "Zero address"); keeper = _keeper; emit SetKeeper(_keeper); } function setSwapHandlerAddresses( address _BalancerVault, address _WETH, address _Univ3Router ) external onlyOwner { swapHandlerAddresses.BalancerVault = _BalancerVault; swapHandlerAddresses.WETH = _WETH; swapHandlerAddresses.Univ3Router = _Univ3Router; emit HandlerAddressesChanged(_BalancerVault); } function setAllowedVault(address _vault, bool _allowed) external onlyOwner { require(_vault != address(0), "Vault address cannot be 0"); allowedVaults[_vault] = _allowed; } function setChainlinkOracleForAsset(address _token, address _oracle) external onlyOwner { require(_token != address(0), "Zero address"); chainlinkOracle[_token] = _oracle; emit ChainlinkOracleSet(_token, _oracle); } function setInterestRate( uint256 _ceilSlope1, uint256 _ceilSlope2, uint256 _maxInterestSlope1, uint256 _maxInterestSlope2, uint256 _baseInterestRate ) external onlyOwner { require(_ceilSlope1 < _ceilSlope2, "Invalid ceilSlope1 and ceilSlope2"); require(_maxInterestSlope1 < _maxInterestSlope2, "Invalid maxInterestSlope1 and maxInterestSlope2"); interestRateConfig.CEIL_SLOPE_1 = _ceilSlope1; interestRateConfig.CEIL_SLOPE_2 = _ceilSlope2; interestRateConfig.MAX_INTEREST_SLOPE_1 = _maxInterestSlope1; interestRateConfig.MAX_INTEREST_SLOPE_2 = _maxInterestSlope2; interestRateConfig.baseInterestRate = _baseInterestRate; emit InterestParamsChanged(_ceilSlope1, _ceilSlope2, _maxInterestSlope1, _maxInterestSlope2, _baseInterestRate); } function setStrategyRouterSwapPath( address _strategy, address[11] memory _routerSwapPathIn, address[11] memory _routerSwapPathOut ) external onlyOwner { curveRouterSwapPath[_strategy] = CurveRouterSwapPath(_routerSwapPathIn, _routerSwapPathOut); strategyIsRouterPath[_strategy] = true; emit StrategyRouterSet(_strategy, _routerSwapPathIn, _routerSwapPathOut); } function setCurveRouter(address _CurveRouter) external onlyOwner { require(_CurveRouter != address(0), "Zero address"); CurveRouter = _CurveRouter; emit CurveRouterSet(_CurveRouter); } function setStrategyToCurvePools( address _strategy, address[5] memory _curvePoolsIn, address[5] memory _curvePoolOut ) external onlyOwner { curvePools[_strategy] = CurvePools(_curvePoolsIn, _curvePoolOut); emit StrategyToCurvePoolsInSet(_strategy, _curvePoolsIn, _curvePoolOut); } function setCurvePoolsSwapPaths( address _strategy, uint256[5][5] memory _swapPathIn, uint256[5][5] memory _swapPathOut ) external onlyOwner { curvePoolsSwapPaths[_strategy] = CurvePoolsSwapPaths(_swapPathIn, _swapPathOut); emit SwapPathSet(_strategy, _swapPathIn, _swapPathOut); } //-- View functions --// function getCurveInAndOutPools( address _strategy ) external view returns (CurvePools memory) { return curvePools[_strategy]; } function getCurveRouterSwapPath(address _strategy) external view returns (CurveRouterSwapPath memory) { return curveRouterSwapPath[_strategy]; } function getCurvePoolsSwapPaths( address _strategy ) external view returns (CurvePoolsSwapPaths memory) { return curvePoolsSwapPaths[_strategy]; } function getUserInfo(address _user, uint256 _positionID, address _AirPuffVault) public view returns (IAirPuffVaultM.UserInfo memory) { return IAirPuffVaultM(_AirPuffVault).userInfo(_user,_positionID); } function getUserTimestamp(address _user, uint256 _positionID, address _AirPuffVault) public view returns (IAirPuffVaultM.PositionTimestamps memory) { return IAirPuffVaultM(_AirPuffVault).positionTimestamps(_user,_positionID); } function getPositionWithInterestRate(address _user, uint256 _positionID, address _AirPuffVault) public view returns (uint256,uint256) { require(allowedVaults[_AirPuffVault], 'Not an allowed vault'); IAirPuffVaultM.UserInfo memory _userInfo = getUserInfo(_user, _positionID, _AirPuffVault); IAirPuffVaultM.PositionTimestamps memory _positionTimestamps = getUserTimestamp(_user, _positionID, _AirPuffVault); uint256 timestamp = _positionTimestamps.openTimestamp; address positionLendingVault = IAirPuffVaultM(_AirPuffVault).LendingVault(); uint256 positionAmount = _userInfo.leverageAmount; uint256 positionEnteredSnapshot = _positionTimestamps.vaultSnapshotID; uint256 currentSnapshot = vaultCurrentSnapshotID[positionLendingVault]; uint256 accruedInterests; for (uint256 i = positionEnteredSnapshot; i <= currentSnapshot; i++) { RateSnapshot memory rs = rateSnapshots[positionLendingVault][i]; RateSnapshot memory rsAdd = rateSnapshots[positionLendingVault][i+1]; uint256 interests = rs.rate; if (i != currentSnapshot){ uint256 timeElapsed; if(i == positionEnteredSnapshot){ timeElapsed = rsAdd.timestamp - timestamp; } else { timeElapsed = rsAdd.timestamp - rs.timestamp; } accruedInterests += interests * timeElapsed / 365 days; } else { uint256 timeElapsed; if (i == positionEnteredSnapshot) { timeElapsed = block.timestamp - timestamp; } else { timeElapsed = block.timestamp - rs.timestamp; } accruedInterests += interests * timeElapsed / 365 days; } } // @note The USDC vault has 6 decimals uint256 posDebtValueWithInterests = positionAmount * (1e18 + accruedInterests) / 1e18; uint256 totalInterests = posDebtValueWithInterests - positionAmount; return (posDebtValueWithInterests, totalInterests); } function getLatestData(address _token) public view returns (uint256) { (, /* uint80 roundID */ int answer /*uint startedAt*/ /*uint timeStamp*/ /*uint80 answeredInRound*/, , , ) = AggregatorV3Interface( chainlinkOracle[_token] ).latestRoundData(); //in 1e8 uint256 decimals = AggregatorV3Interface(chainlinkOracle[_token]).decimals(); if(decimals != 18) { return uint256(answer) * 10**(18 - decimals); } else { return uint256(answer); } } function getAnyAssetPrice(address _token, address _strategy) public view returns (uint256) { if (chainlinkOracle[_token] != address(0)) { uint256 chPrice = getLatestData(_token); return chPrice; } else { uint256 finalPrice; if (isVectorStrategy[_strategy]) { finalPrice = IVectorOracle(VectorOracle).consultvETHPrice(); } else { address assetToOracle; try IAirPuffVaultM(_strategy).strategyAddresses() { IAirPuffVaultM.StrategyAddresses memory sa = IAirPuffVaultM(_strategy).strategyAddresses(); assetToOracle = sa.API3Oracle; (int224 price,) = IAPI3Oracle(assetToOracle).read(); uint256 LRTAssetPrice = abi.decode(abi.encode(price), (uint256)); finalPrice = LRTAssetPrice; } catch { revert("No oracle set for this strategy"); } } return finalPrice; } } function getAnySlippagedAmountOut(address _assetFrom, address _to, uint256 _amount, address _strategy, bool _close) public view returns (uint256) { uint256 assetOutPrice; if (isVectorStrategy[_strategy]) { assetOutPrice = IVectorOracle(VectorOracle).consultvETHPrice(); } else { if (!_close) { assetOutPrice = getAnyAssetPrice(_to, _strategy); } else { assetOutPrice = getAnyAssetPrice(_assetFrom, _strategy); } } uint256 pricedInAssetAmount; uint256 amountOutMin; if (assetOutPrice != 0) { if (!_close) { pricedInAssetAmount = _amount * 1e18 / assetOutPrice; amountOutMin = pricedInAssetAmount - (pricedInAssetAmount * uniswapSlippage / 1000); } else { pricedInAssetAmount = _amount * assetOutPrice / 1e18; amountOutMin = pricedInAssetAmount - (pricedInAssetAmount * uniswapSlippage / 1000); } return amountOutMin; } else { return 0; } } function getInterestRate(address _lendingVault) public view returns (uint256) { uint256 utilRate = ILending(_lendingVault).getUtilizationRate(); uint256 interestRatePercent; if (utilRate <= interestRateConfig.CEIL_SLOPE_1) { interestRatePercent = interestRateConfig.baseInterestRate + (1e18 - (interestRateConfig.CEIL_SLOPE_1 - utilRate)) * interestRateConfig.MAX_INTEREST_SLOPE_1 /1e18; } else { interestRatePercent = (interestRateConfig.baseInterestRate + interestRateConfig.MAX_INTEREST_SLOPE_1 + ((utilRate - interestRateConfig.CEIL_SLOPE_1) * (interestRateConfig.MAX_INTEREST_SLOPE_2 - interestRateConfig.MAX_INTEREST_SLOPE_1)) / (interestRateConfig.CEIL_SLOPE_2 - interestRateConfig.CEIL_SLOPE_1)); } return interestRatePercent; } // -- Admin functions --// function takeInterestsSnapshot(address _AirPuffVault) public onlyKeeper { require(allowedVaults[_AirPuffVault], 'Not an allowed vault'); address lendingVault = IAirPuffVaultM(_AirPuffVault).LendingVault(); vaultCurrentSnapshotID[lendingVault]++; RateSnapshot storage rs = rateSnapshots[lendingVault][vaultCurrentSnapshotID[lendingVault]]; uint256 interestRate = getInterestRate(lendingVault); rs.rate = interestRate; rs.snapshotID = vaultCurrentSnapshotID[lendingVault]; rs.timestamp = block.timestamp; emit SnapshotTaken(); } // -- Reserved functions --// function handlerSwap(bool _isSimple,uint256 _amount,address _assetFrom,address _assetTo, bool _isClose, bool _isBalancer) external returns (uint256){ require(allowedVaults[msg.sender], 'Not an allowed vault'); uint256 amountOut; if (StrategyToCurvePool[msg.sender] != address(0)) { if (strategyIsRouterPath[msg.sender]) { amountOut = _curveRouterSwapWithPaths(_amount, _isClose, _assetTo, _assetFrom); } else { amountOut = _curveSimpleSwap(_assetFrom, _amount, _assetTo, _isClose); } } else { if (_isBalancer) { if (_isSimple) { amountOut = _swapBalancerSimple(_amount, _assetFrom, _assetTo, _isClose); } else { amountOut = _swapBalancerMulti(_amount, _assetFrom, _assetTo, _isClose); } } else { amountOut = _uniswapExecution(_amount, _assetFrom, _assetTo, _isClose); } } return amountOut; } function _curveSimpleSwap( address _assetFrom, uint256 dx, address _assetTo, bool _isClose ) internal returns (uint256 dy) { require(StrategyToCurvePool[msg.sender] != address(0), 'No curve pool set for this strategy'); address curvePool = StrategyToCurvePool[msg.sender]; address asset0 = ICurveStableSwapNG(StrategyToCurvePool[msg.sender]).coins(0); int128 i; int128 j; if (asset0 == _assetFrom) { i = 0; j = 1; } else { i = 1; j = 0; } IERC20Upgradeable(_assetFrom).approve(curvePool, dx); uint256 amountOutMin = getAnySlippagedAmountOut(_assetFrom, _assetTo, dx, msg.sender, _isClose); require(amountOutMin > 0, "Slippage too high"); dy = ICurveStableSwapNG(curvePool).exchange(i, j, dx, amountOutMin, msg.sender); return dy; } function _curveRouterSwapWithPaths( uint256 _amount, bool _isClose, address _assetTo, address _assetFrom) internal returns (uint256) { address[11] memory route; address[5] memory _curvePools; uint256[5][5] memory swap_params; if (!_isClose) { require( curvePools[msg.sender].curvePoolsIn.length > 0, "No curve pool/routes set for this strategy" ); route = curveRouterSwapPath[msg.sender].routeIn; _curvePools = curvePools[msg.sender].curvePoolsIn; swap_params = curvePoolsSwapPaths[msg.sender].swapPathsIn; } else { require( curvePools[msg.sender].curvePoolsOut.length > 0, "No curve pool/routes set for this strategy" ); route = curveRouterSwapPath[msg.sender].routeOut; _curvePools = curvePools[msg.sender].curvePoolsOut; swap_params = curvePoolsSwapPaths[msg.sender].swapPathsOut; } uint256 balBefore = IERC20Upgradeable(_assetTo).balanceOf( address(this) ); IERC20Upgradeable(_assetFrom).approve(CurveRouter, _amount); uint256 amountOutMin = getAnySlippagedAmountOut(_assetFrom, _assetTo, _amount, msg.sender, _isClose); require(amountOutMin > 0, "Slippage too high"); ICurveRouter(CurveRouter).exchange( route, swap_params, _amount, amountOutMin, _curvePools ); uint256 balAfter = IERC20Upgradeable(_assetTo).balanceOf(address(this)); uint256 amountOut = balAfter - balBefore; IERC20Upgradeable(_assetTo).safeTransfer(msg.sender, amountOut); return amountOut; } function _swapBalancerSimple( uint256 _amount, address _assetFrom, address _assetTo, bool _isClosed ) internal returns (uint256) { IERC20Upgradeable(_assetFrom).safeIncreaseAllowance(swapHandlerAddresses.BalancerVault, _amount); uint256 amountOutMin = getAnySlippagedAmountOut(_assetFrom, _assetTo, _amount, msg.sender, _isClosed); int256 encodedOut; unchecked { encodedOut = int256(amountOutMin); } require(encodedOut > 0, "Slippage too high"); IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](1); swaps[0] = IBalancerVault.BatchSwapStep({ poolId: balancerInPoolID[msg.sender], // First pool ID assetInIndex: 0, assetOutIndex: 1, amount: _amount, userData: "0x" }); // Assuming 3 assets are involved: _assetFrom, LRTAsset, and _assetTo IAsset[] memory assets = new IAsset[](2); assets[0] = IAsset(_assetFrom); assets[1] = IAsset(_assetTo); IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({ sender: address(this), fromInternalBalance: false, recipient: payable(msg.sender), toInternalBalance: false }); // Adjust limits to accommodate for the intermediary asset int256[] memory limits = new int256[](2); limits[0] = int256(_amount); // Maximum amount of `_assetFrom` to spend limits[1] = -encodedOut; // Minimum amount of `_assetTo` to receive, set to -1 to not specify // Perform the batch swap int256[] memory assetDeltas = IBalancerVault(swapHandlerAddresses.BalancerVault).batchSwap( IBalancerVault.SwapKind.GIVEN_IN, swaps, assets, funds, limits, block.timestamp + balancerDeadline // deadline ); // Assuming `assetDeltas[1]` will be negative, representing the amount of `_assetTo` received. // Convert it to positive to return the amount out. return uint256(-assetDeltas[1]); } function _swapBalancerMulti( uint256 _amount, address _assetFrom, address _assetTo, bool _isClose ) internal returns (uint256) { uint256 amountOutMin = getAnySlippagedAmountOut(_assetFrom, _assetTo, _amount, msg.sender, _isClose); int256 encodedOut; unchecked { encodedOut = int256(amountOutMin); } require(encodedOut > 0, "Slippage too high"); IERC20Upgradeable(_assetFrom).safeIncreaseAllowance(swapHandlerAddresses.BalancerVault, _amount); bytes32 poolID1; bytes32 poolID2; if (_isClose) { poolID1 = balancerOutPoolID[msg.sender]; poolID2 = balancerInPoolID[msg.sender]; } else { poolID1 = balancerInPoolID[msg.sender]; poolID2 = balancerOutPoolID[msg.sender]; } IBalancerVault.BatchSwapStep[] memory swaps = new IBalancerVault.BatchSwapStep[](2); swaps[0] = IBalancerVault.BatchSwapStep({ poolId: poolID1, // First pool ID assetInIndex: 0, assetOutIndex: 1, amount: _amount, userData: "0x" }); swaps[1] = IBalancerVault.BatchSwapStep({ poolId: poolID2, // Second pool ID assetInIndex: 1, assetOutIndex: 2, amount: 0, // for GIVEN_IN, amount is only relevant in the first step userData: "0x" }); // Assuming 3 assets are involved: _assetFrom, LRTAsset, and _assetTo IAsset[] memory assets = new IAsset[](3); assets[0] = IAsset(_assetFrom); // This needs to be the intermediary asset; replace `LRTAsset` with the actual address assets[1] = IAsset(StrategyToLRT[msg.sender]); assets[2] = IAsset(_assetTo); IBalancerVault.FundManagement memory funds = IBalancerVault.FundManagement({ sender: address(this), fromInternalBalance: false, recipient: payable(msg.sender), toInternalBalance: false }); // Adjust limits to accommodate for the intermediary asset int256[] memory limits = new int256[](3); limits[0] = int256(_amount); // Maximum amount of `_assetFrom` to spend limits[1] = int256(0); // Set to 0 or another value based on your strategy for the intermediary asset limits[2] = -encodedOut; // Minimum amount of `_assetTo` to receive, set to -1 to not specify // Perform the batch swap int256[] memory assetDeltas = IBalancerVault(swapHandlerAddresses.BalancerVault).batchSwap( IBalancerVault.SwapKind.GIVEN_IN, swaps, assets, funds, limits, block.timestamp + balancerDeadline // deadline ); // Assuming `assetDeltas[2]` will be negative, representing the amount of `_assetTo` received. // Convert it to positive to return the amount out. return uint256(-assetDeltas[2]); } function _uniswapExecution( uint256 _amount, address _assetFrom, address _assetTo, bool _isClose ) internal returns (uint256) { IERC20Upgradeable(_assetFrom).approve(swapHandlerAddresses.Univ3Router, _amount); uint256 amountOutMin = getAnySlippagedAmountOut(_assetFrom, _assetTo, _amount, msg.sender, _isClose); require(amountOutMin > 0, "Slippage too high"); ISwapRouter.ExactInputSingleParams memory params = ISwapRouter .ExactInputSingleParams({ tokenIn: _assetFrom, tokenOut: _assetTo, fee: uniFee, recipient: msg.sender, deadline: block.timestamp, amountIn: _amount, amountOutMinimum: amountOutMin, sqrtPriceLimitX96: 0 }); uint256 amountOut = ISwapRouter(swapHandlerAddresses.Univ3Router).exactInputSingle(params); return amountOut; } receive() external payable {} }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData( uint80 _roundId ) external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); function latestRoundData() external view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface IAPI3Oracle { function read() external view returns (int224 value, uint32 timestamp); function getExchangeRate() external view returns (uint256); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface IAirPuffVaultM { struct UserInfo { address user; uint256 deposit; uint256 leverage; uint256 position; bool liquidated; address liquidator; uint256 leverageAmount; uint256 positionId; bool closed; } struct PositionTimestamps { uint256 openTimestamp; uint256 closeTimestamp; uint256 vaultSnapshotID; } function getAllLendingVaults() external view returns (address[] memory); function userInfo(address _user,uint256 _positionID) external view returns (UserInfo memory); function positionTimestamps(address _user,uint256 _positionID) external view returns (PositionTimestamps memory); function LendingVault() external view returns (address); function strategyAddresses() external view returns (StrategyAddresses memory); struct StrategyAddresses { address LRTAsset; address WETH; address API3Oracle; address AirPuffHandler; address borrowAsset; } }
//SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.21; interface ILending { function lend(uint256 _borrowed, address _receiver) external returns (bool status); function repayDebt(uint256 leverage, uint256 debtValue) external returns (bool); function getTotalDebt() external view returns (uint256); function updateTotalDebt(uint256 profit) external returns (uint256); function totalAssets() external view returns (uint256); function totalDebt() external view returns (uint256); function balanceOfUSDC() external view returns (uint256); function getUtilizationRate() external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @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) (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.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.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @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 IERC20PermitUpgradeable { /** * @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.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable { using AddressUpgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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( IERC20PermitUpgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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))) && AddressUpgradeable.isContract(address(token)); } }
// 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); } } }
// 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) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { 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); } } }
{ "remappings": [], "optimizer": { "enabled": true, "runs": 1 }, "evmVersion": "shanghai", "libraries": {}, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"balancerDeadline","type":"uint256"}],"name":"BalancerDeadlineSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"oracle","type":"address"}],"name":"ChainlinkOracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"CurveRouter","type":"address"}],"name":"CurveRouterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_Kyber","type":"address"}],"name":"HandlerAddressesChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"ceilSlope1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"ceilSlope2","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxInterestSlope1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxInterestSlope2","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseInterestRate","type":"uint256"}],"name":"InterestParamsChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"balancerLRTAssetPool","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"balancerMixedLRTPool","type":"bytes32"}],"name":"PoolIDSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"openAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"closedAmount","type":"uint256"}],"name":"RequestFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"keeper","type":"address"}],"name":"SetKeeper","type":"event"},{"anonymous":false,"inputs":[],"name":"SnapshotTaken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"address[11]","name":"routerSwapPathIn","type":"address[11]"},{"indexed":false,"internalType":"address[11]","name":"routerSwapPathOut","type":"address[11]"}],"name":"StrategyRouterSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":true,"internalType":"address","name":"curvePool","type":"address"}],"name":"StrategyToCurvePoolSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"address[5]","name":"curvePoolIn","type":"address[5]"},{"indexed":false,"internalType":"address[5]","name":"curvePoolOut","type":"address[5]"}],"name":"StrategyToCurvePoolsInSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"uint256[5][5]","name":"swappathIn","type":"uint256[5][5]"},{"indexed":false,"internalType":"uint256[5][5]","name":"swappathOut","type":"uint256[5][5]"}],"name":"SwapPathSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint24","name":"uniFee","type":"uint24"}],"name":"UniFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"slippage","type":"uint256"}],"name":"UniswapSlippageSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":true,"internalType":"address","name":"LRTAsset","type":"address"}],"name":"VaultToLRTAssetSet","type":"event"},{"inputs":[],"name":"CurveRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LRTAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"StrategyToCurvePool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"StrategyToLRT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UniswapQuoter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VectorOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedVaults","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balancerDeadline","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balancerInPoolID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balancerLRTAssetPool","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balancerMixedLRTPool","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balancerOutPoolID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"chainlinkOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_strategy","type":"address"}],"name":"getAnyAssetPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_assetFrom","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"bool","name":"_close","type":"bool"}],"name":"getAnySlippagedAmountOut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"getCurveInAndOutPools","outputs":[{"components":[{"internalType":"address[5]","name":"curvePoolsIn","type":"address[5]"},{"internalType":"address[5]","name":"curvePoolsOut","type":"address[5]"}],"internalType":"struct AirPuffHandlerM.CurvePools","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"getCurvePoolsSwapPaths","outputs":[{"components":[{"internalType":"uint256[5][5]","name":"swapPathsIn","type":"uint256[5][5]"},{"internalType":"uint256[5][5]","name":"swapPathsOut","type":"uint256[5][5]"}],"internalType":"struct AirPuffHandlerM.CurvePoolsSwapPaths","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"getCurveRouterSwapPath","outputs":[{"components":[{"internalType":"address[11]","name":"routeIn","type":"address[11]"},{"internalType":"address[11]","name":"routeOut","type":"address[11]"}],"internalType":"struct AirPuffHandlerM.CurveRouterSwapPath","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_lendingVault","type":"address"}],"name":"getInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getLatestData","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_positionID","type":"uint256"},{"internalType":"address","name":"_AirPuffVault","type":"address"}],"name":"getPositionWithInterestRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_positionID","type":"uint256"},{"internalType":"address","name":"_AirPuffVault","type":"address"}],"name":"getUserInfo","outputs":[{"components":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"leverage","type":"uint256"},{"internalType":"uint256","name":"position","type":"uint256"},{"internalType":"bool","name":"liquidated","type":"bool"},{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"uint256","name":"leverageAmount","type":"uint256"},{"internalType":"uint256","name":"positionId","type":"uint256"},{"internalType":"bool","name":"closed","type":"bool"}],"internalType":"struct IAirPuffVaultM.UserInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_positionID","type":"uint256"},{"internalType":"address","name":"_AirPuffVault","type":"address"}],"name":"getUserTimestamp","outputs":[{"components":[{"internalType":"uint256","name":"openTimestamp","type":"uint256"},{"internalType":"uint256","name":"closeTimestamp","type":"uint256"},{"internalType":"uint256","name":"vaultSnapshotID","type":"uint256"}],"internalType":"struct IAirPuffVaultM.PositionTimestamps","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isSimple","type":"bool"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_assetFrom","type":"address"},{"internalType":"address","name":"_assetTo","type":"address"},{"internalType":"bool","name":"_isClose","type":"bool"},{"internalType":"bool","name":"_isBalancer","type":"bool"}],"name":"handlerSwap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateConfig","outputs":[{"internalType":"uint256","name":"CEIL_SLOPE_1","type":"uint256"},{"internalType":"uint256","name":"CEIL_SLOPE_2","type":"uint256"},{"internalType":"uint256","name":"MAX_INTEREST_SLOPE_1","type":"uint256"},{"internalType":"uint256","name":"MAX_INTEREST_SLOPE_2","type":"uint256"},{"internalType":"uint256","name":"baseInterestRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isVectorStrategy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"rateSnapshots","outputs":[{"internalType":"uint256","name":"rate","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"snapshotID","type":"uint256"},{"internalType":"uint256","name":"closeTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setAllowedVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_balancerDeadline","type":"uint256"}],"name":"setBalancerDeadline","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_oracle","type":"address"}],"name":"setChainlinkOracleForAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"uint256[5][5]","name":"_swapPathIn","type":"uint256[5][5]"},{"internalType":"uint256[5][5]","name":"_swapPathOut","type":"uint256[5][5]"}],"name":"setCurvePoolsSwapPaths","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_CurveRouter","type":"address"}],"name":"setCurveRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ceilSlope1","type":"uint256"},{"internalType":"uint256","name":"_ceilSlope2","type":"uint256"},{"internalType":"uint256","name":"_maxInterestSlope1","type":"uint256"},{"internalType":"uint256","name":"_maxInterestSlope2","type":"uint256"},{"internalType":"uint256","name":"_baseInterestRate","type":"uint256"}],"name":"setInterestRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"bool","name":"_isVector","type":"bool"}],"name":"setIsVectorStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_balancerPoolIn","type":"bytes32"},{"internalType":"bytes32","name":"_balancerPoolOut","type":"bytes32"},{"internalType":"address","name":"_strategy","type":"address"}],"name":"setStrategyPoolID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address[11]","name":"_routerSwapPathIn","type":"address[11]"},{"internalType":"address[11]","name":"_routerSwapPathOut","type":"address[11]"}],"name":"setStrategyRouterSwapPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address","name":"_curvePool","type":"address"}],"name":"setStrategyToCurvePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address[5]","name":"_curvePoolsIn","type":"address[5]"},{"internalType":"address[5]","name":"_curvePoolOut","type":"address[5]"}],"name":"setStrategyToCurvePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_BalancerVault","type":"address"},{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"address","name":"_Univ3Router","type":"address"}],"name":"setSwapHandlerAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_uniFee","type":"uint24"}],"name":"setUniFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_slippage","type":"uint256"}],"name":"setUniswapSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"address","name":"_LRT","type":"address"}],"name":"setVaultToLRT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_VectorOracle","type":"address"}],"name":"setVectorOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"strategyIsRouterPath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapHandlerAddresses","outputs":[{"internalType":"address","name":"BalancerVault","type":"address"},{"internalType":"address","name":"WETH","type":"address"},{"internalType":"address","name":"Univ3Router","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_AirPuffVault","type":"address"}],"name":"takeInterestsSnapshot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniFee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"uniswapSlippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaultCurrentSnapshotID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801562000010575f80fd5b506200001b62000021565b620000df565b5f54610100900460ff16156200008d5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811614620000dd575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b614a5580620000ed5f395ff3fe60806040526004361061027d575f3560e01c8063030f7cec146102885780630f127ea8146102bd57806313f7cf5a146102fc5780631919e78b1461031d57806319e5bd98146103545780631b493061146103815780631f0c2122146103b5578063237882bd146103e257806324090e8e146103f757806325ca9e561461041657806329069e93146104575780632c2a5126146104765780632f085bd8146104ac578063324f0120146104cb57806336dbbc40146104ea578063395aef8e146105095780634a1711901461053d5780634a5d6c751461055c5780634eca1fe51461058857806352abf0b5146105a857806357ff1f43146105c757806359803929146105f65780635c975abb14610615578063682138261461062c5780636bbdc24b14610641578063715018a61461066057806371df870f14610674578063741d636914610689578063748747e6146106b55780637642c169146106d4578063805a288f146107095780638129fc1c14610728578063891790361461073c57806389ee8ec01461075b5780638d3f04b2146107715780638da5cb5b14610790578063983c3ee6146107a457806398e1b31b146107fa578063a1c58ba614610826578063a2f652e414610845578063aced166114610864578063ad18ca5514610883578063b21b23e0146108af578063bb1bc4aa1461091a578063bc668a0014610945578063c0be7f6b14610964578063cc66246614610983578063ccff854b146109a2578063cd45537d146109c1578063d3ea0f89146109f5578063d84a23bc14610a14578063e8d76bce14610a40578063f2f201dc14610a6e578063f2fde38b14610a8d578063f388744714610aac578063f4cba1a014610acb575f80fd5b3661028457005b5f80fd5b348015610293575f80fd5b506102a76102a2366004613a77565b610aeb565b6040516102b49190613abd565b60405180910390f35b3480156102c8575f80fd5b506102ec6102d7366004613a77565b6101186020525f908152604090205460ff1681565b60405190151581526020016102b4565b348015610307575f80fd5b5061031b610316366004613be4565b610b95565b005b348015610328575f80fd5b5060d15460d25460d35460d45460d554610343949392919085565b6040516102b4959493929190613c2a565b34801561035f575f80fd5b5061011654610374906001600160a01b031681565b6040516102b49190613c4d565b34801561038c575f80fd5b506103a061039b366004613c61565b610c53565b604080519283526020830191909152016102b4565b3480156103c0575f80fd5b506103d46103cf366004613cad565b610f12565b6040519081526020016102b4565b3480156103ed575f80fd5b506103d460cb5481565b348015610402575f80fd5b5061031b610411366004613d67565b611088565b348015610421575f80fd5b50610435610430366004613c61565b611120565b60408051825181526020808401519082015291810151908201526060016102b4565b348015610462575f80fd5b506103d4610471366004613da3565b6111b8565b348015610481575f80fd5b5060cc5461049890600160a01b900462ffffff1681565b60405162ffffff90911681526020016102b4565b3480156104b7575f80fd5b5061031b6104c6366004613a77565b61127b565b3480156104d6575f80fd5b5061031b6104e5366004613e18565b6112f3565b3480156104f5575f80fd5b5061031b610504366004613e55565b611375565b348015610514575f80fd5b50610374610523366004613a77565b60d76020525f90815260409020546001600160a01b031681565b348015610548575f80fd5b5061031b610557366004613e8c565b6113d4565b348015610567575f80fd5b5061057b610576366004613a77565b6114fc565b6040516102b49190613f1a565b348015610593575f80fd5b5061011454610374906001600160a01b031681565b3480156105b3575f80fd5b5061031b6105c2366004613a77565b6115f2565b3480156105d2575f80fd5b506102ec6105e1366004613a77565b6101136020525f908152604090205460ff1681565b348015610601575f80fd5b5061031b610610366004613f40565b611643565b348015610620575f80fd5b5060975460ff166102ec565b348015610637575f80fd5b506103d460ca5481565b34801561064c575f80fd5b5061031b61065b366004613f40565b611676565b34801561066b575f80fd5b5061031b6116fa565b34801561067f575f80fd5b506103d460cd5481565b348015610694575f80fd5b506103d46106a3366004613a77565b61010f6020525f908152604090205481565b3480156106c0575f80fd5b5061031b6106cf366004613a77565b61170d565b3480156106df575f80fd5b506103746106ee366004613a77565b61010d6020525f90815260409020546001600160a01b031681565b348015610714575f80fd5b5061031b610723366004613f6c565b611784565b348015610733575f80fd5b5061031b6117e5565b348015610747575f80fd5b5061031b610756366004614023565b611953565b348015610766575f80fd5b506103d46101155481565b34801561077c575f80fd5b5061031b61078b366004614060565b6119eb565b34801561079b575f80fd5b50610374611a50565b3480156107af575f80fd5b5060ce5460cf5460d0546107d0926001600160a01b03908116928116911683565b604080516001600160a01b03948516815292841660208401529216918101919091526060016102b4565b348015610805575f80fd5b50610819610814366004613c61565b611a5f565b6040516102b4919061408b565b348015610831575f80fd5b506103d4610840366004613e55565b611b29565b348015610850575f80fd5b5061031b61085f366004614113565b611db3565b34801561086f575f80fd5b5060c954610374906001600160a01b031681565b34801561088e575f80fd5b506103d461089d366004613a77565b61010e6020525f908152604090205481565b3480156108ba575f80fd5b506108fa6108c936600461412a565b60d860209081525f928352604080842090915290825290208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016102b4565b348015610925575f80fd5b506103d4610934366004613a77565b60d96020525f908152604090205481565b348015610950575f80fd5b5061031b61095f366004614113565b611df0565b34801561096f575f80fd5b5061031b61097e366004613e55565b611e72565b34801561098e575f80fd5b5061031b61099d366004613e55565b611ed0565b3480156109ad575f80fd5b5060cc54610374906001600160a01b031681565b3480156109cc575f80fd5b506103746109db366004613a77565b60da6020525f90815260409020546001600160a01b031681565b348015610a00575f80fd5b506103d4610a0f366004613a77565b611f6a565b348015610a1f575f80fd5b50610a33610a2e366004613a77565b61208b565b6040516102b4919061417f565b348015610a4b575f80fd5b506102ec610a5a366004613a77565b60d66020525f908152604090205460ff1681565b348015610a79575f80fd5b506103d4610a88366004613a77565b612134565b348015610a98575f80fd5b5061031b610aa7366004613a77565b61226d565b348015610ab7575f80fd5b5061031b610ac6366004613a77565b6122e3565b348015610ad6575f80fd5b5061011754610374906001600160a01b031681565b610af3613814565b6001600160a01b0382165f908152610111602052604090819020815160e08101835291829081018260058282826020028201915b81546001600160a01b03168152600190910190602001808311610b275750505091835250506040805160a08101918290526020909201919060058481019182845b81546001600160a01b03168152600190910190602001808311610b68575050505050815250509050919050565b610b9d612475565b60408051808201825283815260208082018490526001600160a01b0386165f908152610110909152919091208151610bd8908290600b613839565b506020820151610bee90600b8084019190613839565b5050506001600160a01b0383165f818152610113602052604090819020805460ff19166001179055517f2ed65ece039f8020d5c5f72f6ebbda598e4883c1cd8311cde2a077ea0e94d92090610c4690859085906141a5565b60405180910390a2505050565b6001600160a01b0381165f90815260d66020526040812054819060ff16610c955760405162461bcd60e51b8152600401610c8c906141c2565b60405180910390fd5b5f610ca1868686611a5f565b90505f610caf878787611120565b90505f815f015190505f866001600160a01b03166378fc88506040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cf5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d199190614200565b60c08501516040808601516001600160a01b0384165f90815260d960205291822054939450919290825b828111610ec6576001600160a01b0386165f81815260d860208181526040808420868552808352818520825160808101845281548152600180830154828701526002830154948201949094526003909101546060820152958552929091528290610dae90869061422f565b81526020019081526020015f206040518060800160405290815f8201548152602001600182015481526020016002820154815260200160038201548152505090505f825f01519050858414610e5e575f878503610e1c578a8360200151610e159190614242565b9050610e33565b83602001518360200151610e309190614242565b90505b6301e13380610e428284614255565b610e4c919061426c565b610e56908761422f565b955050610eb0565b5f878503610e7757610e708b42614242565b9050610e89565b6020840151610e869042614242565b90505b6301e13380610e988284614255565b610ea2919061426c565b610eac908761422f565b9550505b5050508080610ebe9061428b565b915050610d43565b505f670de0b6b3a7640000610edb838261422f565b610ee59087614255565b610eef919061426c565b90505f610efc8683614242565b919f919e50909c50505050505050505050505050565b6001600160a01b0382165f9081526101186020526040812054819060ff1615610fb1576101175f9054906101000a90046001600160a01b03166001600160a01b0316635d66c0b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f86573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faa91906142a3565b9050610fcd565b82610fc057610faa8685611b29565b610fca8785611b29565b90505b5f80821561107857846110265782610fed88670de0b6b3a7640000614255565b610ff7919061426c565b91506103e8610115548361100b9190614255565b611015919061426c565b61101f9083614242565b905061106e565b670de0b6b3a76400006110398489614255565b611043919061426c565b91506103e861011554836110579190614255565b611061919061426c565b61106b9083614242565b90505b925061107f915050565b5f93505050505b95945050505050565b611090612475565b60408051808201825283815260208082018490526001600160a01b0386165f9081526101119091529190912081516110cb9082906005613891565b5060208201516110e19060058084019190613891565b50905050826001600160a01b03167f2e32c6aa6b9f2fdd1e9b5c012e2dd4292b60047bf27a317d7f239665dee040468383604051610c469291906142ba565b61114160405180606001604052805f81526020015f81526020015f81525090565b604051633c46de5560e21b81526001600160a01b0383169063f11b79549061116f90879087906004016142d6565b606060405180830381865afa15801561118a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ae91906142ef565b90505b9392505050565b335f90815260d6602052604081205460ff166111e65760405162461bcd60e51b8152600401610c8c906141c2565b335f90815261010d60205260408120546001600160a01b03161561123b57335f908152610113602052604090205460ff161561122f57611228878587896124d4565b905061126e565b6112288688878761292a565b821561125f5787156112535761122887878787612b78565b61122887878787612e47565b61126b87878787613206565b90505b90505b9695505050505050565b611283612475565b6001600160a01b0381166112a95760405162461bcd60e51b8152600401610c8c90614348565b61011480546001600160a01b0319166001600160a01b0383169081179091556040517f17eb51c788501d789e67453168fa440388b0988fe4b0ba593c6c5815fa6bd04a905f90a250565b6112fb612475565b60ce80546001600160a01b038086166001600160a01b03199283161790925560cf805485841690831617905560d08054928416929091169190911790556040517f2af4d8456862888732c1107e93d932b30673eea122415692e4d10a5a9e030f2a90611368908590613c4d565b60405180910390a1505050565b61137d612475565b6001600160a01b038281165f81815261010d602052604080822080546001600160a01b0319169486169485179055517fefe8eaf49c10d8d11e3ba3e4fdcbcb421bb07bd50ccaa186e7809502e31b88769190a35050565b6113dc612475565b8385106114355760405162461bcd60e51b815260206004820152602160248201527f496e76616c6964206365696c536c6f70653120616e64206365696c536c6f70656044820152601960f91b6064820152608401610c8c565b81831061149c5760405162461bcd60e51b815260206004820152602f60248201527f496e76616c6964206d6178496e746572657374536c6f70653120616e64206d6160448201526e3c24b73a32b932b9ba29b637b8329960891b6064820152608401610c8c565b60d185905560d284905560d383905560d482905560d58190556040517f19ef90f3af90e2042c82a378c8847d1ee6e8a6e126eededc605c384a14714e08906114ed9087908790879087908790613c2a565b60405180910390a15050505050565b6115046138d8565b6001600160a01b0382165f9081526101126020526040808220815160e0810183529290918391908201908390600590835b8282101561157c576040805160a081019182905290600584810287019182845b81548152602001906001019080831161155557505050505081526020019060010190611535565b505050908252506040805160a081019091526020909101906019830160055f835b828210156115e4576040805160a081019182905290600584810287019182845b8154815260200190600101908083116115bd5750505050508152602001906001019061159d565b505050915250909392505050565b6115fa612475565b6001600160a01b0381166116205760405162461bcd60e51b8152600401610c8c90614348565b61011780546001600160a01b0319166001600160a01b0392909216919091179055565b61164b612475565b6001600160a01b03919091165f90815261011860205260409020805460ff1916911515919091179055565b61167e612475565b6001600160a01b0382166116d05760405162461bcd60e51b815260206004820152601960248201527805661756c7420616464726573732063616e6e6f74206265203603c1b6044820152606401610c8c565b6001600160a01b03919091165f90815260d660205260409020805460ff1916911515919091179055565b611702612475565b61170b5f6133b4565b565b611715612475565b6001600160a01b03811661173b5760405162461bcd60e51b8152600401610c8c90614348565b60c980546001600160a01b0319166001600160a01b0383169081179091556040517fefb5cfa1a8690c124332ab93324539c5c9c4be03f28aeb8be86f2d8a0c9fb99b905f90a250565b61178c612475565b60cc805462ffffff60a01b1916600160a01b62ffffff8416908102919091179091556040519081527f3edf7c5842f3d38c32fa64c8ef7ffb3dc24d390e2b0ee27ee5fae2fb86ca518c906020015b60405180910390a150565b5f54610100900460ff161580801561180357505f54600160ff909116105b80611823575061181230613405565b15801561182357505f5460ff166001145b6118865760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610c8c565b5f805460ff1916600117905580156118a7575f805461ff0019166101001790555b66b1a2bc2ec5000060d555670b1a2bc2ec50000060d155670de0b6b3a764000060d25567016345785d8a000060d355670429d069189e000060d45560cc805462ffffff60a01b1916607d60a21b1790556118ff613414565b611907613442565b61190f613470565b8015611950575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016117da565b50565b61195b612475565b60408051808201825283815260208082018490526001600160a01b0386165f90815261011290915291909120815161199690829060056138f8565b5060208201516119ac90601983019060056138f8565b50905050826001600160a01b03167f09c01519f8e08ce6dd47f9d9bab00537faa9e6b72dea084c5134b9a06c857ca48383604051610c4692919061436e565b6119f3612475565b6001600160a01b0381165f90815261010e6020908152604080832086905561010f82529182902084905581518581529081018490527fae8cfb17cfc19776abbb6da292fdaf859fb0ca6370319e4dacc6f33bf0f17dd29101611368565b6033546001600160a01b031690565b611abb6040518061012001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f151581526020015f6001600160a01b031681526020015f81526020015f81526020015f151581525090565b6040516321ce919d60e01b81526001600160a01b038316906321ce919d90611ae990879087906004016142d6565b61012060405180830381865afa158015611b05573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ae9190614396565b6001600160a01b038281165f90815260d7602052604081205490911615611b5d575f611b5484612134565b9150611dad9050565b6001600160a01b0382165f908152610118602052604081205460ff1615611bfa576101175f9054906101000a90046001600160a01b03166001600160a01b0316635d66c0b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bcf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bf391906142a3565b9050611daa565b5f836001600160a01b031663100e196d6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015611c55575060408051601f3d908101601f19168201909252611c5291810190614427565b60015b611ca15760405162461bcd60e51b815260206004820152601f60248201527f4e6f206f7261636c652073657420666f722074686973207374726174656779006044820152606401610c8c565b505f846001600160a01b031663100e196d6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611cdf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d039190614427565b9050806040015191505f826001600160a01b03166357de26a46040518163ffffffff1660e01b81526004016040805180830381865afa158015611d48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d6c91906144bc565b5060408051601b83900b60208201529192505f9101604051602081830303815290604052806020019051810190611da391906142a3565b9450505050505b90505b92915050565b611dbb612475565b60cd8190556040518181527f2c7875836a1fd972539d6b21b622b9a5d7f4893b9bfa4ca5b34b22f2b491b53a906020016117da565b611df8612475565b6064811115611e3c5760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420736c69707061676560801b6044820152606401610c8c565b6101158190556040518181527fa88f36de2bff4046f61cf527b24fb235f9ea07fe213ba179b8bd7ea0bb343d50906020016117da565b611e7a612475565b6001600160a01b038281165f81815260da602052604080822080546001600160a01b0319169486169485179055517ff2f844af49949a48ac5da4e3ea9def7881041fab5abd755ac35a5332e6cfd2079190a35050565b611ed8612475565b6001600160a01b038216611efe5760405162461bcd60e51b8152600401610c8c90614348565b6001600160a01b038281165f90815260d760205260409081902080546001600160a01b03191692841692909217909155517fafdfd513be71799b20ea13372c27dacb2e35615c8031a10bb6970412890ef0d390611f5e90849084906144f6565b60405180910390a15050565b5f80826001600160a01b0316634a417a536040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fa8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fcc91906142a3565b90505f60d15f015482116120305760d35460d154670de0b6b3a76400009190611ff6908590614242565b61200890670de0b6b3a7640000614242565b6120129190614255565b61201c919061426c565b60d554612029919061422f565b90506111b1565b60d15460d2546120409190614242565b60d35460d4546120509190614242565b60d15461205d9085614242565b6120679190614255565b612071919061426c565b60d35460d554612081919061422f565b6111ae919061422f565b61209361393f565b6001600160a01b0382165f90815261011060205260409081902081516101a081018352918290810182600b8282826020028201915b81546001600160a01b031681526001909101906020018083116120c857505050918352505060408051610160810191829052600b84810180546001600160a01b0316835260209485019492939092600c8701908501808311610b68575050505050815250509050919050565b6001600160a01b038082165f90815260d76020526040808220548151633fabe5a360e21b815291519293849391169163feaf968c9160048083019260a09291908290030181865afa15801561218b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121af9190614526565b5050506001600160a01b038086165f90815260d76020908152604080832054815163313ce56760e01b81529151959750929550919092169263313ce567926004808401939192918290030181865afa15801561220d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122319190614572565b60ff1690508060121461226657612249816012614242565b61225490600a614672565b61225e9083614255565b949350505050565b5092915050565b612275612475565b6001600160a01b0381166122da5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c8c565b611950816133b4565b60c9546001600160a01b0316331461232b5760405162461bcd60e51b815260206004820152600b60248201526a27b7363c9025b2b2b832b960a91b6044820152606401610c8c565b6001600160a01b0381165f90815260d6602052604090205460ff166123625760405162461bcd60e51b8152600401610c8c906141c2565b5f816001600160a01b03166378fc88506040518163ffffffff1660e01b8152600401602060405180830381865afa15801561239f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c39190614200565b6001600160a01b0381165f90815260d9602052604081208054929350906123e98361428b565b90915550506001600160a01b0381165f90815260d86020908152604080832060d9835281842054845290915281209061242183611f6a565b8083556001600160a01b0384165f90815260d96020526040808220546002860155426001860155519192507fa4516bb177b5e755530944ec3cd87484284e0c48f908adbf1c09486b32a1c35f91a150505050565b3361247e611a50565b6001600160a01b03161461170b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c8c565b5f6124dd61395b565b6124e561397a565b6124ed613998565b866125f557335f908152610110602052604090819020815161016081019283905291600b9082845b81546001600160a01b03168152600190910190602001808311612515575050335f908152610111602052604090819020815160a0810192839052959850935060059250905082845b81546001600160a01b0316815260019091019060200180831161255d575050335f9081526101126020526040808220815160a08101909252959750949350600592509050835b828210156125ea576040805160a081019182905290600584810287019182845b8154815260200190600101908083116125c3575050505050815260200190600101906125a3565b5050505090506126fe565b335f908152610110602052604090819020815161016081019283905291600b918201919082845b81546001600160a01b0316815260019091019060200180831161261c575050335f908152610111602052604090819020815160a0810192839052959850600590810194509250905082845b81546001600160a01b03168152600190910190602001808311612667575050335f9081526101126020526040808220815160a08101909252959750946019019350600592509050835b828210156126f7576040805160a081019182905290600584810287019182845b8154815260200190600101908083116126d0575050505050815260200190600101906126b0565b5050505090505b6040516370a0823160e01b81525f906001600160a01b038816906370a082319061272c903090600401613c4d565b602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b91906142a3565b6101145460405163095ea7b360e01b81529192506001600160a01b038089169263095ea7b3926127a19216908d906004016142d6565b6020604051808303815f875af11580156127bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127e1919061467d565b505f6127f087898c338d610f12565b90505f81116128115760405162461bcd60e51b8152600401610c8c90614698565b61011454604051632e4e0c7160e11b81526001600160a01b0390911690635c9c18e29061284a90889087908f9087908b906004016146c3565b6020604051808303815f875af1158015612866573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288a91906142a3565b506040516370a0823160e01b81525f906001600160a01b038a16906370a08231906128b9903090600401613c4d565b602060405180830381865afa1580156128d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128f891906142a3565b90505f6129058483614242565b905061291b6001600160a01b038b16338361349e565b9b9a5050505050505050505050565b335f90815261010d60205260408120546001600160a01b031661299b5760405162461bcd60e51b815260206004820152602360248201527f4e6f20637572766520706f6f6c2073657420666f72207468697320737472617460448201526265677960e81b6064820152608401610c8c565b335f90815261010d602052604080822054905163c661065760e01b8152600481018390526001600160a01b039091169190829063c661065790602401602060405180830381865afa1580156129f2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a169190614200565b90505f80886001600160a01b0316836001600160a01b031603612a3e57505f90506001612a45565b50600190505f5b60405163095ea7b360e01b81526001600160a01b038a169063095ea7b390612a739087908c906004016142d6565b6020604051808303815f875af1158015612a8f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ab3919061467d565b505f612ac28a898b338b610f12565b90505f8111612ae35760405162461bcd60e51b8152600401610c8c90614698565b60405163ddc1f59d60e01b8152600f84810b600483015283900b6024820152604481018a9052606481018290523360848201526001600160a01b0386169063ddc1f59d9060a4016020604051808303815f875af1158015612b46573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b6a91906142a3565b9a9950505050505050505050565b60ce545f90612b94906001600160a01b038681169116876134f9565b5f612ba28585883387610f12565b9050805f8113612bc45760405162461bcd60e51b8152600401610c8c90614698565b6040805160018082528183019092525f91816020015b612be26139c5565b815260200190600190039081612bda5790505090506040518060a0016040528061010e5f336001600160a01b03166001600160a01b031681526020019081526020015f205481526020015f81526020016001815260200189815260200160405180604001604052806002815260200161060f60f31b815250815250815f81518110612c6f57612c6f6146fc565b6020908102919091010152604080516002808252606082019092525f9181602001602082028036833701905050905087815f81518110612cb157612cb16146fc565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600181518110612ce557612ce56146fc565b6001600160a01b0392909216602092830291909101820152604080516080810182523081525f81840181905233828401526060808301829052835160028082529181018552929491939091830190803683370190505090508a815f81518110612d5057612d506146fc565b6020908102919091010152612d6485614710565b81600181518110612d7757612d776146fc565b602090810291909101015260ce5460cd545f916001600160a01b03169063945bcec99083908890889088908890612dae904261422f565b6040518763ffffffff1660e01b8152600401612dcf969594939291906147e7565b5f604051808303815f875af1158015612dea573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612e119190810190614913565b905080600181518110612e2657612e266146fc565b6020026020010151612e3790614710565b9c9b505050505050505050505050565b5f80612e568585883387610f12565b9050805f8113612e785760405162461bcd60e51b8152600401610c8c90614698565b60ce54612e92906001600160a01b038881169116896134f9565b5f808515612ebe575050335f90815261010f602090815260408083205461010e90925290912054612ede565b5050335f90815261010e602090815260408083205461010f909252909120545b604080516002808252606082019092525f91816020015b612efd6139c5565b815260200190600190039081612ef55790505090506040518060a001604052808481526020015f8152602001600181526020018b815260200160405180604001604052806002815260200161060f60f31b815250815250815f81518110612f6657612f666146fc565b60200260200101819052506040518060a0016040528083815260200160018152602001600281526020015f815260200160405180604001604052806002815260200161060f60f31b81525081525081600181518110612fc757612fc76146fc565b6020908102919091010152604080516003808252608082019092525f9181602001602082028036833701905050905089815f81518110613009576130096146fc565b6001600160a01b03928316602091820292909201810191909152335f90815260da909152604090205482519116908290600190811061304a5761304a6146fc565b60200260200101906001600160a01b031690816001600160a01b031681525050888160028151811061307e5761307e6146fc565b6001600160a01b039290921660209283029190910182015260408051608080820183523082525f93820184905233828401526060820184905282516003808252918101909352909291908160200160208202803683370190505090508c815f815181106130ed576130ed6146fc565b6020026020010181815250505f8160018151811061310d5761310d6146fc565b602090810291909101015261312187614710565b81600281518110613134576131346146fc565b602090810291909101015260ce5460cd545f916001600160a01b03169063945bcec9908390889088908890889061316b904261422f565b6040518763ffffffff1660e01b815260040161318c969594939291906147e7565b5f604051808303815f875af11580156131a7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526131ce9190810190614913565b9050806002815181106131e3576131e36146fc565b60200260200101516131f490614710565b9e9d5050505050505050505050505050565b60d05460405163095ea7b360e01b81525f916001600160a01b038087169263095ea7b39261323a92169089906004016142d6565b6020604051808303815f875af1158015613256573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061327a919061467d565b505f6132898585883387610f12565b90505f81116132aa5760405162461bcd60e51b8152600401610c8c90614698565b60408051610100810182526001600160a01b0387811682528681166020830190815260cc54600160a01b900462ffffff9081168486019081523360608601908152426080870190815260a087018e815260c088018a81525f60e08a0181815260d0549b5163414bf38960e01b81528b518b16600482015298518a1660248a015295519096166044880152925187166064870152905160848601525160a48501525160c484015251831660e483015292939091169063414bf38990610104016020604051808303815f875af1158015613384573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133a891906142a3565b98975050505050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b03163b151590565b5f54610100900460ff1661343a5760405162461bcd60e51b8152600401610c8c906149a7565b61170b613598565b5f54610100900460ff166134685760405162461bcd60e51b8152600401610c8c906149a7565b61170b6135c7565b5f54610100900460ff166134965760405162461bcd60e51b8152600401610c8c906149a7565b61170b6135f9565b6134f48363a9059cbb60e01b84846040516024016134bd9291906142d6565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613626565b505050565b604051636eb1769f60e11b81525f906001600160a01b0385169063dd62ed3e9061352990309087906004016144f6565b602060405180830381865afa158015613544573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061356891906142a3565b90506135928463095ea7b360e01b85613581868661422f565b6040516024016134bd9291906142d6565b50505050565b5f54610100900460ff166135be5760405162461bcd60e51b8152600401610c8c906149a7565b61170b336133b4565b5f54610100900460ff166135ed5760405162461bcd60e51b8152600401610c8c906149a7565b6097805460ff19169055565b5f54610100900460ff1661361f5760405162461bcd60e51b8152600401610c8c906149a7565b6001606555565b5f61367a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136f99092919063ffffffff16565b905080515f148061369a57508080602001905181019061369a919061467d565b6134f45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c8c565b60606111ae84845f85855f80866001600160a01b0316858760405161371e91906149f2565b5f6040518083038185875af1925050503d805f8114613758576040519150601f19603f3d011682016040523d82523d5f602084013e61375d565b606091505b509150915061376e87838387613779565b979650505050505050565b606083156137e55782515f036137de5761379285613405565b6137de5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c8c565b508161225e565b61225e83838151156137fa5781518083602001fd5b8060405162461bcd60e51b8152600401610c8c9190614a0d565b604051806040016040528061382761397a565b815260200161383461397a565b905290565b82600b8101928215613881579160200282015b8281111561388157825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061384c565b5061388d9291506139f3565b5090565b8260058101928215613881579160200282018281111561388157825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061384c565b60405180604001604052806138eb613998565b8152602001613834613998565b601983019183908215613933579160200282015b828111156139335782516139239083906005613a07565b509160200191906005019061390c565b5061388d929150613a35565b604051806040016040528061395261395b565b81526020016138345b604051806101600160405280600b906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b6040518060a001604052806005905b6139af61397a565b8152602001906001900390816139a75790505090565b6040518060a001604052805f80191681526020015f81526020015f81526020015f8152602001606081525090565b5b8082111561388d575f81556001016139f4565b8260058101928215613881579160200282015b82811115613881578251825591602001919060010190613a1a565b8082111561388d575f8082556001820181905560028201819055600382018190556004820155600501613a35565b6001600160a01b0381168114611950575f80fd5b5f60208284031215613a87575f80fd5b81356111b181613a63565b805f5b60058110156135925781516001600160a01b0316845260209384019390910190600101613a95565b5f61014082019050613ad0828451613a92565b602083015161226660a0840182613a92565b634e487b7160e01b5f52604160045260245ffd5b60405161012081016001600160401b0381118282101715613b1957613b19613ae2565b60405290565b60405160a081016001600160401b0381118282101715613b1957613b19613ae2565b604051601f8201601f191681016001600160401b0381118282101715613b6957613b69613ae2565b604052919050565b5f82601f830112613b80575f80fd5b6040516101608082016001600160401b0381118382101715613ba457613ba4613ae2565b60405283018185821115613bb6575f80fd5b845b82811015613bd9578035613bcb81613a63565b825260209182019101613bb8565b509195945050505050565b5f805f6102e08486031215613bf7575f80fd5b8335613c0281613a63565b9250613c118560208601613b71565b9150613c21856101808601613b71565b90509250925092565b948552602085019390935260408401919091526060830152608082015260a00190565b6001600160a01b0391909116815260200190565b5f805f60608486031215613c73575f80fd5b8335613c7e81613a63565b9250602084013591506040840135613c9581613a63565b809150509250925092565b8015158114611950575f80fd5b5f805f805f60a08688031215613cc1575f80fd5b8535613ccc81613a63565b94506020860135613cdc81613a63565b9350604086013592506060860135613cf381613a63565b91506080860135613d0381613ca0565b809150509295509295909350565b5f82601f830112613d20575f80fd5b613d28613b1f565b8060a0840185811115613d39575f80fd5b845b81811015613d5c578035613d4e81613a63565b845260209384019301613d3b565b509095945050505050565b5f805f6101608486031215613d7a575f80fd5b8335613d8581613a63565b9250613d948560208601613d11565b9150613c218560c08601613d11565b5f805f805f8060c08789031215613db8575f80fd5b8635613dc381613ca0565b9550602087013594506040870135613dda81613a63565b93506060870135613dea81613a63565b92506080870135613dfa81613ca0565b915060a0870135613e0a81613ca0565b809150509295509295509295565b5f805f60608486031215613e2a575f80fd5b8335613e3581613a63565b92506020840135613e4581613a63565b91506040840135613c9581613a63565b5f8060408385031215613e66575f80fd5b8235613e7181613a63565b91506020830135613e8181613a63565b809150509250929050565b5f805f805f60a08688031215613ea0575f80fd5b505083359560208501359550604085013594606081013594506080013592509050565b805f805b6005808210613ed65750613f13565b835186845b83811015613ef9578251825260209283019290910190600101613edb565b50505060a095909501945060209290920191600101613ec7565b5050505050565b5f61064082019050613f2d828451613ec3565b6020830151612266610320840182613ec3565b5f8060408385031215613f51575f80fd5b8235613f5c81613a63565b91506020830135613e8181613ca0565b5f60208284031215613f7c575f80fd5b813562ffffff811681146111b1575f80fd5b5f601f8381840112613f9e575f80fd5b613fa6613b1f565b80610320850186811115613fb8575f80fd5b855b81811015614017578785820112613fd0575f8081fd5b613fd8613b1f565b8060a083018a811115613fea575f8081fd5b835b81811015614004578035845260209384019301613fec565b505085525060209093019260a001613fba565b50909695505050505050565b5f805f6106608486031215614036575f80fd5b833561404181613a63565b92506140508560208601613f8e565b9150613c21856103408601613f8e565b5f805f60608486031215614072575f80fd5b83359250602084013591506040840135613c9581613a63565b81516001600160a01b0316815260208083015190820152604080830151908201526060808301519082015260808083015115159082015260a0828101516101208301916140e2908401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015161410b8285018215159052565b505092915050565b5f60208284031215614123575f80fd5b5035919050565b5f806040838503121561413b575f80fd5b823561414681613a63565b946020939093013593505050565b805f5b600b8110156135925781516001600160a01b0316845260209384019390910190600101614157565b5f6102c082019050614192828451614154565b6020830151612266610160840182614154565b6102c081016141b48285614154565b6111b1610160830184614154565b602080825260149082015273139bdd08185b88185b1b1bddd959081d985d5b1d60621b604082015260600190565b80516141fb81613a63565b919050565b5f60208284031215614210575f80fd5b81516111b181613a63565b634e487b7160e01b5f52601160045260245ffd5b80820180821115611dad57611dad61421b565b81810381811115611dad57611dad61421b565b8082028115828204841417611dad57611dad61421b565b5f8261428657634e487b7160e01b5f52601260045260245ffd5b500490565b5f6001820161429c5761429c61421b565b5060010190565b5f602082840312156142b3575f80fd5b5051919050565b61014081016142c98285613a92565b6111b160a0830184613a92565b6001600160a01b03929092168252602082015260400190565b5f606082840312156142ff575f80fd5b604051606081016001600160401b038111828210171561432157614321613ae2565b80604052508251815260208301516020820152604083015160408201528091505092915050565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b610640810161437d8285613ec3565b6111b1610320830184613ec3565b80516141fb81613ca0565b5f61012082840312156143a7575f80fd5b6143af613af6565b6143b8836141f0565b81526020830151602082015260408301516040820152606083015160608201526143e46080840161438b565b60808201526143f560a084016141f0565b60a082015260c083015160c082015260e083015160e082015261010061441c81850161438b565b908201529392505050565b5f60a08284031215614437575f80fd5b60405160a081016001600160401b038111828210171561445957614459613ae2565b604052825161446781613a63565b8152602083015161447781613a63565b6020820152604083015161448a81613a63565b6040820152606083015161449d81613a63565b606082015260808301516144b081613a63565b60808201529392505050565b5f80604083850312156144cd575f80fd5b825180601b0b81146144dd575f80fd5b602084015190925063ffffffff81168114613e81575f80fd5b6001600160a01b0392831681529116602082015260400190565b80516001600160501b03811681146141fb575f80fd5b5f805f805f60a0868803121561453a575f80fd5b61454386614510565b945060208601519350604086015192506060860151915061456660808701614510565b90509295509295909350565b5f60208284031215614582575f80fd5b815160ff811681146111b1575f80fd5b600181815b808511156145cc57815f19048211156145b2576145b261421b565b808516156145bf57918102915b93841c9390800290614597565b509250929050565b5f826145e257506001611dad565b816145ee57505f611dad565b8160018114614604576002811461460e5761462a565b6001915050611dad565b60ff84111561461f5761461f61421b565b50506001821b611dad565b5060208310610133831016604e8410600b841016171561464d575081810a611dad565b6146578383614592565b805f190482111561466a5761466a61421b565b029392505050565b5f6111b183836145d4565b5f6020828403121561468d575f80fd5b81516111b181613ca0565b6020808252601190820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604082015260600190565b61056081016146d28288614154565b6146e0610160830187613ec3565b84610480830152836104a08301526112716104c0830184613a92565b634e487b7160e01b5f52603260045260245ffd5b5f600160ff1b82016147245761472461421b565b505f0390565b5f5b8381101561474457818101518382015260200161472c565b50505f910152565b5f815180845261476381602086016020860161472a565b601f01601f19169290920160200192915050565b5f8151808452602080850194508084015f5b838110156147ae5781516001600160a01b031687529582019590820190600101614789565b509495945050505050565b5f8151808452602080850194508084015f5b838110156147ae578151875295820195908201906001016147cb565b5f61012080830160028a1061480a57634e487b7160e01b5f52602160045260245ffd5b89845260208085019290925288519081905261014080850192600583901b8601909101918a82015f5b828110156148965787850361013f190186528151805186528481015185870152604080820151908701526060808201519087015260809081015160a0918701829052906148828188018361474c565b978601979650505090830190600101614833565b5050505083810360408501526148ac8189614777565b9150506148ec606084018780516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b82810360e08401526148fe81866147b9565b91505082610100830152979650505050505050565b5f6020808385031215614924575f80fd5b82516001600160401b038082111561493a575f80fd5b818501915085601f83011261494d575f80fd5b81518181111561495f5761495f613ae2565b8060051b9150614970848301613b41565b8181529183018401918481019088841115614989575f80fd5b938501935b838510156133a85784518252938501939085019061498e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f8251614a0381846020870161472a565b9190910192915050565b602081525f6111b1602083018461474c56fea2646970667358221220da8232655639d032eae9b8cbba173fae360c81ec1433349e5dbfcb390b2dff1c64736f6c63430008150033
Deployed Bytecode
0x60806040526004361061027d575f3560e01c8063030f7cec146102885780630f127ea8146102bd57806313f7cf5a146102fc5780631919e78b1461031d57806319e5bd98146103545780631b493061146103815780631f0c2122146103b5578063237882bd146103e257806324090e8e146103f757806325ca9e561461041657806329069e93146104575780632c2a5126146104765780632f085bd8146104ac578063324f0120146104cb57806336dbbc40146104ea578063395aef8e146105095780634a1711901461053d5780634a5d6c751461055c5780634eca1fe51461058857806352abf0b5146105a857806357ff1f43146105c757806359803929146105f65780635c975abb14610615578063682138261461062c5780636bbdc24b14610641578063715018a61461066057806371df870f14610674578063741d636914610689578063748747e6146106b55780637642c169146106d4578063805a288f146107095780638129fc1c14610728578063891790361461073c57806389ee8ec01461075b5780638d3f04b2146107715780638da5cb5b14610790578063983c3ee6146107a457806398e1b31b146107fa578063a1c58ba614610826578063a2f652e414610845578063aced166114610864578063ad18ca5514610883578063b21b23e0146108af578063bb1bc4aa1461091a578063bc668a0014610945578063c0be7f6b14610964578063cc66246614610983578063ccff854b146109a2578063cd45537d146109c1578063d3ea0f89146109f5578063d84a23bc14610a14578063e8d76bce14610a40578063f2f201dc14610a6e578063f2fde38b14610a8d578063f388744714610aac578063f4cba1a014610acb575f80fd5b3661028457005b5f80fd5b348015610293575f80fd5b506102a76102a2366004613a77565b610aeb565b6040516102b49190613abd565b60405180910390f35b3480156102c8575f80fd5b506102ec6102d7366004613a77565b6101186020525f908152604090205460ff1681565b60405190151581526020016102b4565b348015610307575f80fd5b5061031b610316366004613be4565b610b95565b005b348015610328575f80fd5b5060d15460d25460d35460d45460d554610343949392919085565b6040516102b4959493929190613c2a565b34801561035f575f80fd5b5061011654610374906001600160a01b031681565b6040516102b49190613c4d565b34801561038c575f80fd5b506103a061039b366004613c61565b610c53565b604080519283526020830191909152016102b4565b3480156103c0575f80fd5b506103d46103cf366004613cad565b610f12565b6040519081526020016102b4565b3480156103ed575f80fd5b506103d460cb5481565b348015610402575f80fd5b5061031b610411366004613d67565b611088565b348015610421575f80fd5b50610435610430366004613c61565b611120565b60408051825181526020808401519082015291810151908201526060016102b4565b348015610462575f80fd5b506103d4610471366004613da3565b6111b8565b348015610481575f80fd5b5060cc5461049890600160a01b900462ffffff1681565b60405162ffffff90911681526020016102b4565b3480156104b7575f80fd5b5061031b6104c6366004613a77565b61127b565b3480156104d6575f80fd5b5061031b6104e5366004613e18565b6112f3565b3480156104f5575f80fd5b5061031b610504366004613e55565b611375565b348015610514575f80fd5b50610374610523366004613a77565b60d76020525f90815260409020546001600160a01b031681565b348015610548575f80fd5b5061031b610557366004613e8c565b6113d4565b348015610567575f80fd5b5061057b610576366004613a77565b6114fc565b6040516102b49190613f1a565b348015610593575f80fd5b5061011454610374906001600160a01b031681565b3480156105b3575f80fd5b5061031b6105c2366004613a77565b6115f2565b3480156105d2575f80fd5b506102ec6105e1366004613a77565b6101136020525f908152604090205460ff1681565b348015610601575f80fd5b5061031b610610366004613f40565b611643565b348015610620575f80fd5b5060975460ff166102ec565b348015610637575f80fd5b506103d460ca5481565b34801561064c575f80fd5b5061031b61065b366004613f40565b611676565b34801561066b575f80fd5b5061031b6116fa565b34801561067f575f80fd5b506103d460cd5481565b348015610694575f80fd5b506103d46106a3366004613a77565b61010f6020525f908152604090205481565b3480156106c0575f80fd5b5061031b6106cf366004613a77565b61170d565b3480156106df575f80fd5b506103746106ee366004613a77565b61010d6020525f90815260409020546001600160a01b031681565b348015610714575f80fd5b5061031b610723366004613f6c565b611784565b348015610733575f80fd5b5061031b6117e5565b348015610747575f80fd5b5061031b610756366004614023565b611953565b348015610766575f80fd5b506103d46101155481565b34801561077c575f80fd5b5061031b61078b366004614060565b6119eb565b34801561079b575f80fd5b50610374611a50565b3480156107af575f80fd5b5060ce5460cf5460d0546107d0926001600160a01b03908116928116911683565b604080516001600160a01b03948516815292841660208401529216918101919091526060016102b4565b348015610805575f80fd5b50610819610814366004613c61565b611a5f565b6040516102b4919061408b565b348015610831575f80fd5b506103d4610840366004613e55565b611b29565b348015610850575f80fd5b5061031b61085f366004614113565b611db3565b34801561086f575f80fd5b5060c954610374906001600160a01b031681565b34801561088e575f80fd5b506103d461089d366004613a77565b61010e6020525f908152604090205481565b3480156108ba575f80fd5b506108fa6108c936600461412a565b60d860209081525f928352604080842090915290825290208054600182015460028301546003909301549192909184565b6040805194855260208501939093529183015260608201526080016102b4565b348015610925575f80fd5b506103d4610934366004613a77565b60d96020525f908152604090205481565b348015610950575f80fd5b5061031b61095f366004614113565b611df0565b34801561096f575f80fd5b5061031b61097e366004613e55565b611e72565b34801561098e575f80fd5b5061031b61099d366004613e55565b611ed0565b3480156109ad575f80fd5b5060cc54610374906001600160a01b031681565b3480156109cc575f80fd5b506103746109db366004613a77565b60da6020525f90815260409020546001600160a01b031681565b348015610a00575f80fd5b506103d4610a0f366004613a77565b611f6a565b348015610a1f575f80fd5b50610a33610a2e366004613a77565b61208b565b6040516102b4919061417f565b348015610a4b575f80fd5b506102ec610a5a366004613a77565b60d66020525f908152604090205460ff1681565b348015610a79575f80fd5b506103d4610a88366004613a77565b612134565b348015610a98575f80fd5b5061031b610aa7366004613a77565b61226d565b348015610ab7575f80fd5b5061031b610ac6366004613a77565b6122e3565b348015610ad6575f80fd5b5061011754610374906001600160a01b031681565b610af3613814565b6001600160a01b0382165f908152610111602052604090819020815160e08101835291829081018260058282826020028201915b81546001600160a01b03168152600190910190602001808311610b275750505091835250506040805160a08101918290526020909201919060058481019182845b81546001600160a01b03168152600190910190602001808311610b68575050505050815250509050919050565b610b9d612475565b60408051808201825283815260208082018490526001600160a01b0386165f908152610110909152919091208151610bd8908290600b613839565b506020820151610bee90600b8084019190613839565b5050506001600160a01b0383165f818152610113602052604090819020805460ff19166001179055517f2ed65ece039f8020d5c5f72f6ebbda598e4883c1cd8311cde2a077ea0e94d92090610c4690859085906141a5565b60405180910390a2505050565b6001600160a01b0381165f90815260d66020526040812054819060ff16610c955760405162461bcd60e51b8152600401610c8c906141c2565b60405180910390fd5b5f610ca1868686611a5f565b90505f610caf878787611120565b90505f815f015190505f866001600160a01b03166378fc88506040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cf5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d199190614200565b60c08501516040808601516001600160a01b0384165f90815260d960205291822054939450919290825b828111610ec6576001600160a01b0386165f81815260d860208181526040808420868552808352818520825160808101845281548152600180830154828701526002830154948201949094526003909101546060820152958552929091528290610dae90869061422f565b81526020019081526020015f206040518060800160405290815f8201548152602001600182015481526020016002820154815260200160038201548152505090505f825f01519050858414610e5e575f878503610e1c578a8360200151610e159190614242565b9050610e33565b83602001518360200151610e309190614242565b90505b6301e13380610e428284614255565b610e4c919061426c565b610e56908761422f565b955050610eb0565b5f878503610e7757610e708b42614242565b9050610e89565b6020840151610e869042614242565b90505b6301e13380610e988284614255565b610ea2919061426c565b610eac908761422f565b9550505b5050508080610ebe9061428b565b915050610d43565b505f670de0b6b3a7640000610edb838261422f565b610ee59087614255565b610eef919061426c565b90505f610efc8683614242565b919f919e50909c50505050505050505050505050565b6001600160a01b0382165f9081526101186020526040812054819060ff1615610fb1576101175f9054906101000a90046001600160a01b03166001600160a01b0316635d66c0b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f86573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faa91906142a3565b9050610fcd565b82610fc057610faa8685611b29565b610fca8785611b29565b90505b5f80821561107857846110265782610fed88670de0b6b3a7640000614255565b610ff7919061426c565b91506103e8610115548361100b9190614255565b611015919061426c565b61101f9083614242565b905061106e565b670de0b6b3a76400006110398489614255565b611043919061426c565b91506103e861011554836110579190614255565b611061919061426c565b61106b9083614242565b90505b925061107f915050565b5f93505050505b95945050505050565b611090612475565b60408051808201825283815260208082018490526001600160a01b0386165f9081526101119091529190912081516110cb9082906005613891565b5060208201516110e19060058084019190613891565b50905050826001600160a01b03167f2e32c6aa6b9f2fdd1e9b5c012e2dd4292b60047bf27a317d7f239665dee040468383604051610c469291906142ba565b61114160405180606001604052805f81526020015f81526020015f81525090565b604051633c46de5560e21b81526001600160a01b0383169063f11b79549061116f90879087906004016142d6565b606060405180830381865afa15801561118a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ae91906142ef565b90505b9392505050565b335f90815260d6602052604081205460ff166111e65760405162461bcd60e51b8152600401610c8c906141c2565b335f90815261010d60205260408120546001600160a01b03161561123b57335f908152610113602052604090205460ff161561122f57611228878587896124d4565b905061126e565b6112288688878761292a565b821561125f5787156112535761122887878787612b78565b61122887878787612e47565b61126b87878787613206565b90505b90505b9695505050505050565b611283612475565b6001600160a01b0381166112a95760405162461bcd60e51b8152600401610c8c90614348565b61011480546001600160a01b0319166001600160a01b0383169081179091556040517f17eb51c788501d789e67453168fa440388b0988fe4b0ba593c6c5815fa6bd04a905f90a250565b6112fb612475565b60ce80546001600160a01b038086166001600160a01b03199283161790925560cf805485841690831617905560d08054928416929091169190911790556040517f2af4d8456862888732c1107e93d932b30673eea122415692e4d10a5a9e030f2a90611368908590613c4d565b60405180910390a1505050565b61137d612475565b6001600160a01b038281165f81815261010d602052604080822080546001600160a01b0319169486169485179055517fefe8eaf49c10d8d11e3ba3e4fdcbcb421bb07bd50ccaa186e7809502e31b88769190a35050565b6113dc612475565b8385106114355760405162461bcd60e51b815260206004820152602160248201527f496e76616c6964206365696c536c6f70653120616e64206365696c536c6f70656044820152601960f91b6064820152608401610c8c565b81831061149c5760405162461bcd60e51b815260206004820152602f60248201527f496e76616c6964206d6178496e746572657374536c6f70653120616e64206d6160448201526e3c24b73a32b932b9ba29b637b8329960891b6064820152608401610c8c565b60d185905560d284905560d383905560d482905560d58190556040517f19ef90f3af90e2042c82a378c8847d1ee6e8a6e126eededc605c384a14714e08906114ed9087908790879087908790613c2a565b60405180910390a15050505050565b6115046138d8565b6001600160a01b0382165f9081526101126020526040808220815160e0810183529290918391908201908390600590835b8282101561157c576040805160a081019182905290600584810287019182845b81548152602001906001019080831161155557505050505081526020019060010190611535565b505050908252506040805160a081019091526020909101906019830160055f835b828210156115e4576040805160a081019182905290600584810287019182845b8154815260200190600101908083116115bd5750505050508152602001906001019061159d565b505050915250909392505050565b6115fa612475565b6001600160a01b0381166116205760405162461bcd60e51b8152600401610c8c90614348565b61011780546001600160a01b0319166001600160a01b0392909216919091179055565b61164b612475565b6001600160a01b03919091165f90815261011860205260409020805460ff1916911515919091179055565b61167e612475565b6001600160a01b0382166116d05760405162461bcd60e51b815260206004820152601960248201527805661756c7420616464726573732063616e6e6f74206265203603c1b6044820152606401610c8c565b6001600160a01b03919091165f90815260d660205260409020805460ff1916911515919091179055565b611702612475565b61170b5f6133b4565b565b611715612475565b6001600160a01b03811661173b5760405162461bcd60e51b8152600401610c8c90614348565b60c980546001600160a01b0319166001600160a01b0383169081179091556040517fefb5cfa1a8690c124332ab93324539c5c9c4be03f28aeb8be86f2d8a0c9fb99b905f90a250565b61178c612475565b60cc805462ffffff60a01b1916600160a01b62ffffff8416908102919091179091556040519081527f3edf7c5842f3d38c32fa64c8ef7ffb3dc24d390e2b0ee27ee5fae2fb86ca518c906020015b60405180910390a150565b5f54610100900460ff161580801561180357505f54600160ff909116105b80611823575061181230613405565b15801561182357505f5460ff166001145b6118865760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608401610c8c565b5f805460ff1916600117905580156118a7575f805461ff0019166101001790555b66b1a2bc2ec5000060d555670b1a2bc2ec50000060d155670de0b6b3a764000060d25567016345785d8a000060d355670429d069189e000060d45560cc805462ffffff60a01b1916607d60a21b1790556118ff613414565b611907613442565b61190f613470565b8015611950575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020016117da565b50565b61195b612475565b60408051808201825283815260208082018490526001600160a01b0386165f90815261011290915291909120815161199690829060056138f8565b5060208201516119ac90601983019060056138f8565b50905050826001600160a01b03167f09c01519f8e08ce6dd47f9d9bab00537faa9e6b72dea084c5134b9a06c857ca48383604051610c4692919061436e565b6119f3612475565b6001600160a01b0381165f90815261010e6020908152604080832086905561010f82529182902084905581518581529081018490527fae8cfb17cfc19776abbb6da292fdaf859fb0ca6370319e4dacc6f33bf0f17dd29101611368565b6033546001600160a01b031690565b611abb6040518061012001604052805f6001600160a01b031681526020015f81526020015f81526020015f81526020015f151581526020015f6001600160a01b031681526020015f81526020015f81526020015f151581525090565b6040516321ce919d60e01b81526001600160a01b038316906321ce919d90611ae990879087906004016142d6565b61012060405180830381865afa158015611b05573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ae9190614396565b6001600160a01b038281165f90815260d7602052604081205490911615611b5d575f611b5484612134565b9150611dad9050565b6001600160a01b0382165f908152610118602052604081205460ff1615611bfa576101175f9054906101000a90046001600160a01b03166001600160a01b0316635d66c0b46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611bcf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bf391906142a3565b9050611daa565b5f836001600160a01b031663100e196d6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015611c55575060408051601f3d908101601f19168201909252611c5291810190614427565b60015b611ca15760405162461bcd60e51b815260206004820152601f60248201527f4e6f206f7261636c652073657420666f722074686973207374726174656779006044820152606401610c8c565b505f846001600160a01b031663100e196d6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611cdf573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d039190614427565b9050806040015191505f826001600160a01b03166357de26a46040518163ffffffff1660e01b81526004016040805180830381865afa158015611d48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d6c91906144bc565b5060408051601b83900b60208201529192505f9101604051602081830303815290604052806020019051810190611da391906142a3565b9450505050505b90505b92915050565b611dbb612475565b60cd8190556040518181527f2c7875836a1fd972539d6b21b622b9a5d7f4893b9bfa4ca5b34b22f2b491b53a906020016117da565b611df8612475565b6064811115611e3c5760405162461bcd60e51b815260206004820152601060248201526f496e76616c696420736c69707061676560801b6044820152606401610c8c565b6101158190556040518181527fa88f36de2bff4046f61cf527b24fb235f9ea07fe213ba179b8bd7ea0bb343d50906020016117da565b611e7a612475565b6001600160a01b038281165f81815260da602052604080822080546001600160a01b0319169486169485179055517ff2f844af49949a48ac5da4e3ea9def7881041fab5abd755ac35a5332e6cfd2079190a35050565b611ed8612475565b6001600160a01b038216611efe5760405162461bcd60e51b8152600401610c8c90614348565b6001600160a01b038281165f90815260d760205260409081902080546001600160a01b03191692841692909217909155517fafdfd513be71799b20ea13372c27dacb2e35615c8031a10bb6970412890ef0d390611f5e90849084906144f6565b60405180910390a15050565b5f80826001600160a01b0316634a417a536040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fa8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fcc91906142a3565b90505f60d15f015482116120305760d35460d154670de0b6b3a76400009190611ff6908590614242565b61200890670de0b6b3a7640000614242565b6120129190614255565b61201c919061426c565b60d554612029919061422f565b90506111b1565b60d15460d2546120409190614242565b60d35460d4546120509190614242565b60d15461205d9085614242565b6120679190614255565b612071919061426c565b60d35460d554612081919061422f565b6111ae919061422f565b61209361393f565b6001600160a01b0382165f90815261011060205260409081902081516101a081018352918290810182600b8282826020028201915b81546001600160a01b031681526001909101906020018083116120c857505050918352505060408051610160810191829052600b84810180546001600160a01b0316835260209485019492939092600c8701908501808311610b68575050505050815250509050919050565b6001600160a01b038082165f90815260d76020526040808220548151633fabe5a360e21b815291519293849391169163feaf968c9160048083019260a09291908290030181865afa15801561218b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121af9190614526565b5050506001600160a01b038086165f90815260d76020908152604080832054815163313ce56760e01b81529151959750929550919092169263313ce567926004808401939192918290030181865afa15801561220d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122319190614572565b60ff1690508060121461226657612249816012614242565b61225490600a614672565b61225e9083614255565b949350505050565b5092915050565b612275612475565b6001600160a01b0381166122da5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610c8c565b611950816133b4565b60c9546001600160a01b0316331461232b5760405162461bcd60e51b815260206004820152600b60248201526a27b7363c9025b2b2b832b960a91b6044820152606401610c8c565b6001600160a01b0381165f90815260d6602052604090205460ff166123625760405162461bcd60e51b8152600401610c8c906141c2565b5f816001600160a01b03166378fc88506040518163ffffffff1660e01b8152600401602060405180830381865afa15801561239f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c39190614200565b6001600160a01b0381165f90815260d9602052604081208054929350906123e98361428b565b90915550506001600160a01b0381165f90815260d86020908152604080832060d9835281842054845290915281209061242183611f6a565b8083556001600160a01b0384165f90815260d96020526040808220546002860155426001860155519192507fa4516bb177b5e755530944ec3cd87484284e0c48f908adbf1c09486b32a1c35f91a150505050565b3361247e611a50565b6001600160a01b03161461170b5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610c8c565b5f6124dd61395b565b6124e561397a565b6124ed613998565b866125f557335f908152610110602052604090819020815161016081019283905291600b9082845b81546001600160a01b03168152600190910190602001808311612515575050335f908152610111602052604090819020815160a0810192839052959850935060059250905082845b81546001600160a01b0316815260019091019060200180831161255d575050335f9081526101126020526040808220815160a08101909252959750949350600592509050835b828210156125ea576040805160a081019182905290600584810287019182845b8154815260200190600101908083116125c3575050505050815260200190600101906125a3565b5050505090506126fe565b335f908152610110602052604090819020815161016081019283905291600b918201919082845b81546001600160a01b0316815260019091019060200180831161261c575050335f908152610111602052604090819020815160a0810192839052959850600590810194509250905082845b81546001600160a01b03168152600190910190602001808311612667575050335f9081526101126020526040808220815160a08101909252959750946019019350600592509050835b828210156126f7576040805160a081019182905290600584810287019182845b8154815260200190600101908083116126d0575050505050815260200190600101906126b0565b5050505090505b6040516370a0823160e01b81525f906001600160a01b038816906370a082319061272c903090600401613c4d565b602060405180830381865afa158015612747573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061276b91906142a3565b6101145460405163095ea7b360e01b81529192506001600160a01b038089169263095ea7b3926127a19216908d906004016142d6565b6020604051808303815f875af11580156127bd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127e1919061467d565b505f6127f087898c338d610f12565b90505f81116128115760405162461bcd60e51b8152600401610c8c90614698565b61011454604051632e4e0c7160e11b81526001600160a01b0390911690635c9c18e29061284a90889087908f9087908b906004016146c3565b6020604051808303815f875af1158015612866573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061288a91906142a3565b506040516370a0823160e01b81525f906001600160a01b038a16906370a08231906128b9903090600401613c4d565b602060405180830381865afa1580156128d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128f891906142a3565b90505f6129058483614242565b905061291b6001600160a01b038b16338361349e565b9b9a5050505050505050505050565b335f90815261010d60205260408120546001600160a01b031661299b5760405162461bcd60e51b815260206004820152602360248201527f4e6f20637572766520706f6f6c2073657420666f72207468697320737472617460448201526265677960e81b6064820152608401610c8c565b335f90815261010d602052604080822054905163c661065760e01b8152600481018390526001600160a01b039091169190829063c661065790602401602060405180830381865afa1580156129f2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a169190614200565b90505f80886001600160a01b0316836001600160a01b031603612a3e57505f90506001612a45565b50600190505f5b60405163095ea7b360e01b81526001600160a01b038a169063095ea7b390612a739087908c906004016142d6565b6020604051808303815f875af1158015612a8f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612ab3919061467d565b505f612ac28a898b338b610f12565b90505f8111612ae35760405162461bcd60e51b8152600401610c8c90614698565b60405163ddc1f59d60e01b8152600f84810b600483015283900b6024820152604481018a9052606481018290523360848201526001600160a01b0386169063ddc1f59d9060a4016020604051808303815f875af1158015612b46573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612b6a91906142a3565b9a9950505050505050505050565b60ce545f90612b94906001600160a01b038681169116876134f9565b5f612ba28585883387610f12565b9050805f8113612bc45760405162461bcd60e51b8152600401610c8c90614698565b6040805160018082528183019092525f91816020015b612be26139c5565b815260200190600190039081612bda5790505090506040518060a0016040528061010e5f336001600160a01b03166001600160a01b031681526020019081526020015f205481526020015f81526020016001815260200189815260200160405180604001604052806002815260200161060f60f31b815250815250815f81518110612c6f57612c6f6146fc565b6020908102919091010152604080516002808252606082019092525f9181602001602082028036833701905050905087815f81518110612cb157612cb16146fc565b60200260200101906001600160a01b031690816001600160a01b0316815250508681600181518110612ce557612ce56146fc565b6001600160a01b0392909216602092830291909101820152604080516080810182523081525f81840181905233828401526060808301829052835160028082529181018552929491939091830190803683370190505090508a815f81518110612d5057612d506146fc565b6020908102919091010152612d6485614710565b81600181518110612d7757612d776146fc565b602090810291909101015260ce5460cd545f916001600160a01b03169063945bcec99083908890889088908890612dae904261422f565b6040518763ffffffff1660e01b8152600401612dcf969594939291906147e7565b5f604051808303815f875af1158015612dea573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612e119190810190614913565b905080600181518110612e2657612e266146fc565b6020026020010151612e3790614710565b9c9b505050505050505050505050565b5f80612e568585883387610f12565b9050805f8113612e785760405162461bcd60e51b8152600401610c8c90614698565b60ce54612e92906001600160a01b038881169116896134f9565b5f808515612ebe575050335f90815261010f602090815260408083205461010e90925290912054612ede565b5050335f90815261010e602090815260408083205461010f909252909120545b604080516002808252606082019092525f91816020015b612efd6139c5565b815260200190600190039081612ef55790505090506040518060a001604052808481526020015f8152602001600181526020018b815260200160405180604001604052806002815260200161060f60f31b815250815250815f81518110612f6657612f666146fc565b60200260200101819052506040518060a0016040528083815260200160018152602001600281526020015f815260200160405180604001604052806002815260200161060f60f31b81525081525081600181518110612fc757612fc76146fc565b6020908102919091010152604080516003808252608082019092525f9181602001602082028036833701905050905089815f81518110613009576130096146fc565b6001600160a01b03928316602091820292909201810191909152335f90815260da909152604090205482519116908290600190811061304a5761304a6146fc565b60200260200101906001600160a01b031690816001600160a01b031681525050888160028151811061307e5761307e6146fc565b6001600160a01b039290921660209283029190910182015260408051608080820183523082525f93820184905233828401526060820184905282516003808252918101909352909291908160200160208202803683370190505090508c815f815181106130ed576130ed6146fc565b6020026020010181815250505f8160018151811061310d5761310d6146fc565b602090810291909101015261312187614710565b81600281518110613134576131346146fc565b602090810291909101015260ce5460cd545f916001600160a01b03169063945bcec9908390889088908890889061316b904261422f565b6040518763ffffffff1660e01b815260040161318c969594939291906147e7565b5f604051808303815f875af11580156131a7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526131ce9190810190614913565b9050806002815181106131e3576131e36146fc565b60200260200101516131f490614710565b9e9d5050505050505050505050505050565b60d05460405163095ea7b360e01b81525f916001600160a01b038087169263095ea7b39261323a92169089906004016142d6565b6020604051808303815f875af1158015613256573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061327a919061467d565b505f6132898585883387610f12565b90505f81116132aa5760405162461bcd60e51b8152600401610c8c90614698565b60408051610100810182526001600160a01b0387811682528681166020830190815260cc54600160a01b900462ffffff9081168486019081523360608601908152426080870190815260a087018e815260c088018a81525f60e08a0181815260d0549b5163414bf38960e01b81528b518b16600482015298518a1660248a015295519096166044880152925187166064870152905160848601525160a48501525160c484015251831660e483015292939091169063414bf38990610104016020604051808303815f875af1158015613384573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133a891906142a3565b98975050505050505050565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b03163b151590565b5f54610100900460ff1661343a5760405162461bcd60e51b8152600401610c8c906149a7565b61170b613598565b5f54610100900460ff166134685760405162461bcd60e51b8152600401610c8c906149a7565b61170b6135c7565b5f54610100900460ff166134965760405162461bcd60e51b8152600401610c8c906149a7565b61170b6135f9565b6134f48363a9059cbb60e01b84846040516024016134bd9291906142d6565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613626565b505050565b604051636eb1769f60e11b81525f906001600160a01b0385169063dd62ed3e9061352990309087906004016144f6565b602060405180830381865afa158015613544573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061356891906142a3565b90506135928463095ea7b360e01b85613581868661422f565b6040516024016134bd9291906142d6565b50505050565b5f54610100900460ff166135be5760405162461bcd60e51b8152600401610c8c906149a7565b61170b336133b4565b5f54610100900460ff166135ed5760405162461bcd60e51b8152600401610c8c906149a7565b6097805460ff19169055565b5f54610100900460ff1661361f5760405162461bcd60e51b8152600401610c8c906149a7565b6001606555565b5f61367a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136f99092919063ffffffff16565b905080515f148061369a57508080602001905181019061369a919061467d565b6134f45760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610c8c565b60606111ae84845f85855f80866001600160a01b0316858760405161371e91906149f2565b5f6040518083038185875af1925050503d805f8114613758576040519150601f19603f3d011682016040523d82523d5f602084013e61375d565b606091505b509150915061376e87838387613779565b979650505050505050565b606083156137e55782515f036137de5761379285613405565b6137de5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610c8c565b508161225e565b61225e83838151156137fa5781518083602001fd5b8060405162461bcd60e51b8152600401610c8c9190614a0d565b604051806040016040528061382761397a565b815260200161383461397a565b905290565b82600b8101928215613881579160200282015b8281111561388157825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061384c565b5061388d9291506139f3565b5090565b8260058101928215613881579160200282018281111561388157825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019061384c565b60405180604001604052806138eb613998565b8152602001613834613998565b601983019183908215613933579160200282015b828111156139335782516139239083906005613a07565b509160200191906005019061390c565b5061388d929150613a35565b604051806040016040528061395261395b565b81526020016138345b604051806101600160405280600b906020820280368337509192915050565b6040518060a001604052806005906020820280368337509192915050565b6040518060a001604052806005905b6139af61397a565b8152602001906001900390816139a75790505090565b6040518060a001604052805f80191681526020015f81526020015f81526020015f8152602001606081525090565b5b8082111561388d575f81556001016139f4565b8260058101928215613881579160200282015b82811115613881578251825591602001919060010190613a1a565b8082111561388d575f8082556001820181905560028201819055600382018190556004820155600501613a35565b6001600160a01b0381168114611950575f80fd5b5f60208284031215613a87575f80fd5b81356111b181613a63565b805f5b60058110156135925781516001600160a01b0316845260209384019390910190600101613a95565b5f61014082019050613ad0828451613a92565b602083015161226660a0840182613a92565b634e487b7160e01b5f52604160045260245ffd5b60405161012081016001600160401b0381118282101715613b1957613b19613ae2565b60405290565b60405160a081016001600160401b0381118282101715613b1957613b19613ae2565b604051601f8201601f191681016001600160401b0381118282101715613b6957613b69613ae2565b604052919050565b5f82601f830112613b80575f80fd5b6040516101608082016001600160401b0381118382101715613ba457613ba4613ae2565b60405283018185821115613bb6575f80fd5b845b82811015613bd9578035613bcb81613a63565b825260209182019101613bb8565b509195945050505050565b5f805f6102e08486031215613bf7575f80fd5b8335613c0281613a63565b9250613c118560208601613b71565b9150613c21856101808601613b71565b90509250925092565b948552602085019390935260408401919091526060830152608082015260a00190565b6001600160a01b0391909116815260200190565b5f805f60608486031215613c73575f80fd5b8335613c7e81613a63565b9250602084013591506040840135613c9581613a63565b809150509250925092565b8015158114611950575f80fd5b5f805f805f60a08688031215613cc1575f80fd5b8535613ccc81613a63565b94506020860135613cdc81613a63565b9350604086013592506060860135613cf381613a63565b91506080860135613d0381613ca0565b809150509295509295909350565b5f82601f830112613d20575f80fd5b613d28613b1f565b8060a0840185811115613d39575f80fd5b845b81811015613d5c578035613d4e81613a63565b845260209384019301613d3b565b509095945050505050565b5f805f6101608486031215613d7a575f80fd5b8335613d8581613a63565b9250613d948560208601613d11565b9150613c218560c08601613d11565b5f805f805f8060c08789031215613db8575f80fd5b8635613dc381613ca0565b9550602087013594506040870135613dda81613a63565b93506060870135613dea81613a63565b92506080870135613dfa81613ca0565b915060a0870135613e0a81613ca0565b809150509295509295509295565b5f805f60608486031215613e2a575f80fd5b8335613e3581613a63565b92506020840135613e4581613a63565b91506040840135613c9581613a63565b5f8060408385031215613e66575f80fd5b8235613e7181613a63565b91506020830135613e8181613a63565b809150509250929050565b5f805f805f60a08688031215613ea0575f80fd5b505083359560208501359550604085013594606081013594506080013592509050565b805f805b6005808210613ed65750613f13565b835186845b83811015613ef9578251825260209283019290910190600101613edb565b50505060a095909501945060209290920191600101613ec7565b5050505050565b5f61064082019050613f2d828451613ec3565b6020830151612266610320840182613ec3565b5f8060408385031215613f51575f80fd5b8235613f5c81613a63565b91506020830135613e8181613ca0565b5f60208284031215613f7c575f80fd5b813562ffffff811681146111b1575f80fd5b5f601f8381840112613f9e575f80fd5b613fa6613b1f565b80610320850186811115613fb8575f80fd5b855b81811015614017578785820112613fd0575f8081fd5b613fd8613b1f565b8060a083018a811115613fea575f8081fd5b835b81811015614004578035845260209384019301613fec565b505085525060209093019260a001613fba565b50909695505050505050565b5f805f6106608486031215614036575f80fd5b833561404181613a63565b92506140508560208601613f8e565b9150613c21856103408601613f8e565b5f805f60608486031215614072575f80fd5b83359250602084013591506040840135613c9581613a63565b81516001600160a01b0316815260208083015190820152604080830151908201526060808301519082015260808083015115159082015260a0828101516101208301916140e2908401826001600160a01b03169052565b5060c083015160c083015260e083015160e08301526101008084015161410b8285018215159052565b505092915050565b5f60208284031215614123575f80fd5b5035919050565b5f806040838503121561413b575f80fd5b823561414681613a63565b946020939093013593505050565b805f5b600b8110156135925781516001600160a01b0316845260209384019390910190600101614157565b5f6102c082019050614192828451614154565b6020830151612266610160840182614154565b6102c081016141b48285614154565b6111b1610160830184614154565b602080825260149082015273139bdd08185b88185b1b1bddd959081d985d5b1d60621b604082015260600190565b80516141fb81613a63565b919050565b5f60208284031215614210575f80fd5b81516111b181613a63565b634e487b7160e01b5f52601160045260245ffd5b80820180821115611dad57611dad61421b565b81810381811115611dad57611dad61421b565b8082028115828204841417611dad57611dad61421b565b5f8261428657634e487b7160e01b5f52601260045260245ffd5b500490565b5f6001820161429c5761429c61421b565b5060010190565b5f602082840312156142b3575f80fd5b5051919050565b61014081016142c98285613a92565b6111b160a0830184613a92565b6001600160a01b03929092168252602082015260400190565b5f606082840312156142ff575f80fd5b604051606081016001600160401b038111828210171561432157614321613ae2565b80604052508251815260208301516020820152604083015160408201528091505092915050565b6020808252600c908201526b5a65726f206164647265737360a01b604082015260600190565b610640810161437d8285613ec3565b6111b1610320830184613ec3565b80516141fb81613ca0565b5f61012082840312156143a7575f80fd5b6143af613af6565b6143b8836141f0565b81526020830151602082015260408301516040820152606083015160608201526143e46080840161438b565b60808201526143f560a084016141f0565b60a082015260c083015160c082015260e083015160e082015261010061441c81850161438b565b908201529392505050565b5f60a08284031215614437575f80fd5b60405160a081016001600160401b038111828210171561445957614459613ae2565b604052825161446781613a63565b8152602083015161447781613a63565b6020820152604083015161448a81613a63565b6040820152606083015161449d81613a63565b606082015260808301516144b081613a63565b60808201529392505050565b5f80604083850312156144cd575f80fd5b825180601b0b81146144dd575f80fd5b602084015190925063ffffffff81168114613e81575f80fd5b6001600160a01b0392831681529116602082015260400190565b80516001600160501b03811681146141fb575f80fd5b5f805f805f60a0868803121561453a575f80fd5b61454386614510565b945060208601519350604086015192506060860151915061456660808701614510565b90509295509295909350565b5f60208284031215614582575f80fd5b815160ff811681146111b1575f80fd5b600181815b808511156145cc57815f19048211156145b2576145b261421b565b808516156145bf57918102915b93841c9390800290614597565b509250929050565b5f826145e257506001611dad565b816145ee57505f611dad565b8160018114614604576002811461460e5761462a565b6001915050611dad565b60ff84111561461f5761461f61421b565b50506001821b611dad565b5060208310610133831016604e8410600b841016171561464d575081810a611dad565b6146578383614592565b805f190482111561466a5761466a61421b565b029392505050565b5f6111b183836145d4565b5f6020828403121561468d575f80fd5b81516111b181613ca0565b6020808252601190820152700a6d8d2e0e0c2ceca40e8dede40d0d2ced607b1b604082015260600190565b61056081016146d28288614154565b6146e0610160830187613ec3565b84610480830152836104a08301526112716104c0830184613a92565b634e487b7160e01b5f52603260045260245ffd5b5f600160ff1b82016147245761472461421b565b505f0390565b5f5b8381101561474457818101518382015260200161472c565b50505f910152565b5f815180845261476381602086016020860161472a565b601f01601f19169290920160200192915050565b5f8151808452602080850194508084015f5b838110156147ae5781516001600160a01b031687529582019590820190600101614789565b509495945050505050565b5f8151808452602080850194508084015f5b838110156147ae578151875295820195908201906001016147cb565b5f61012080830160028a1061480a57634e487b7160e01b5f52602160045260245ffd5b89845260208085019290925288519081905261014080850192600583901b8601909101918a82015f5b828110156148965787850361013f190186528151805186528481015185870152604080820151908701526060808201519087015260809081015160a0918701829052906148828188018361474c565b978601979650505090830190600101614833565b5050505083810360408501526148ac8189614777565b9150506148ec606084018780516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b82810360e08401526148fe81866147b9565b91505082610100830152979650505050505050565b5f6020808385031215614924575f80fd5b82516001600160401b038082111561493a575f80fd5b818501915085601f83011261494d575f80fd5b81518181111561495f5761495f613ae2565b8060051b9150614970848301613b41565b8181529183018401918481019088841115614989575f80fd5b938501935b838510156133a85784518252938501939085019061498e565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f8251614a0381846020870161472a565b9190910192915050565b602081525f6111b1602083018461474c56fea2646970667358221220da8232655639d032eae9b8cbba173fae360c81ec1433349e5dbfcb390b2dff1c64736f6c63430008150033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.