Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00Token Holdings
More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 635 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Withdraw | 18642222 | 223 days ago | IN | 0 ETH | 0.00353073 | ||||
Exit | 18637602 | 224 days ago | IN | 0 ETH | 0.00557451 | ||||
Exit | 18635477 | 224 days ago | IN | 0 ETH | 0.00134658 | ||||
Exit | 18635476 | 224 days ago | IN | 0 ETH | 0.0116867 | ||||
Withdraw | 18631558 | 225 days ago | IN | 0 ETH | 0.00353991 | ||||
Exit | 18631553 | 225 days ago | IN | 0 ETH | 0.00912498 | ||||
Withdraw | 18630789 | 225 days ago | IN | 0 ETH | 0.00299065 | ||||
Exit | 18630781 | 225 days ago | IN | 0 ETH | 0.00472215 | ||||
Harvest Multiple... | 18630757 | 225 days ago | IN | 0 ETH | 0.00713542 | ||||
Exit | 18630578 | 225 days ago | IN | 0 ETH | 0.0056825 | ||||
Harvest Multiple... | 18630577 | 225 days ago | IN | 0 ETH | 0.00876244 | ||||
Harvest Multiple... | 18630572 | 225 days ago | IN | 0 ETH | 0.00640309 | ||||
Harvest Multiple... | 18630537 | 225 days ago | IN | 0 ETH | 0.00995844 | ||||
Harvest Multiple... | 18630537 | 225 days ago | IN | 0 ETH | 0.00995844 | ||||
Harvest Multiple... | 18630535 | 225 days ago | IN | 0 ETH | 0.0116061 | ||||
Harvest Multiple... | 18626523 | 225 days ago | IN | 0 ETH | 0.00424678 | ||||
Harvest Multiple... | 18624344 | 226 days ago | IN | 0 ETH | 0.00519859 | ||||
Harvest Multiple... | 18620830 | 226 days ago | IN | 0 ETH | 0.00558616 | ||||
Claim Fee | 18620828 | 226 days ago | IN | 0 ETH | 0.00839428 | ||||
Harvest Multiple... | 18618335 | 227 days ago | IN | 0 ETH | 0.00511331 | ||||
Harvest Multiple... | 18615680 | 227 days ago | IN | 0 ETH | 0.00713843 | ||||
Deposit And Join | 18613265 | 227 days ago | IN | 0 ETH | 0.01103912 | ||||
Join | 18612513 | 227 days ago | IN | 0 ETH | 0.0039271 | ||||
Harvest Multiple... | 18612507 | 227 days ago | IN | 0 ETH | 0.0039631 | ||||
Remove Liquidity | 18610072 | 228 days ago | IN | 0 ETH | 0.00988849 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
KyberSwapElasticLM
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; import {KSMath} from '../libraries/KSMath.sol'; import {IKyberSwapElasticLM} from '../interfaces/liquidityMining/IKyberSwapElasticLM.sol'; import {IKSElasticLMHelper} from '../interfaces/liquidityMining/IKSElasticLMHelper.sol'; import {IBasePositionManager} from '../interfaces/liquidityMining/IBasePositionManager.sol'; import {IPoolStorage} from '../interfaces/liquidityMining/IPoolStorage.sol'; import {KSAdmin} from './base/KSAdmin.sol'; import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol'; import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol'; import {ReentrancyGuard} from '@openzeppelin/contracts/security/ReentrancyGuard.sol'; contract KyberSwapElasticLM is IKyberSwapElasticLM, ReentrancyGuard, KSAdmin { using EnumerableSet for EnumerableSet.UintSet; using SafeERC20 for IERC20Metadata; using KSMath for uint256; IERC721 public immutable nft; IKSElasticLMHelper private helper; address public immutable weth; uint256 internal constant PRECISION = 1e12; uint256 public poolLength; // pId => Pool info mapping(uint256 => LMPoolInfo) public pools; // nftId => Position info mapping(uint256 => PositionInfo) public positions; // nftId => pId => Stake info mapping(uint256 => mapping(uint256 => StakeInfo)) public stakes; // nftId => list of joined pools mapping(uint256 => EnumerableSet.UintSet) internal joinedPools; // user address => set of nft id which user already deposit into LM contract mapping(address => EnumerableSet.UintSet) private depositNFTs; mapping(uint256 => bool) public isEmergencyWithdrawnNFT; bool public emergencyEnabled; bool public specialFeatureEnabled; modifier checkLength(uint256 a, uint256 b) { require(a == b, 'invalid length'); _; } modifier isSpecialFeaturesEnabled() { require(specialFeatureEnabled, 'special feature disabled'); _; } constructor(IERC721 _nft, IKSElasticLMHelper _helper) { nft = _nft; helper = _helper; weth = IBasePositionManager(address(_nft)).WETH(); } /** * EXTERNAL FUNCTIONS ************************* */ /** * @dev receive native reward token */ receive() external payable {} /** * @dev Set emergencyEnabled flag to true */ function emergencyEnable() public isAdmin { require(!emergencyEnabled, 'Invalid value'); emergencyEnabled = true; emit EmergencyEnabled(); } /** * @dev Set specialFeatureEnabled flag to true or false */ function updateSpecialFeatureEnabled(bool enableOrDisable) public isAdmin { specialFeatureEnabled = enableOrDisable; emit UpdateSpecialFeatureEnabled(enableOrDisable); } function updateHelper(IKSElasticLMHelper _helper) external isAdmin { helper = _helper; emit LMHelperUpdated(_helper); } /// @inheritdoc IKyberSwapElasticLM function addPool( address poolAddress, uint32 startTime, uint32 endTime, address[] calldata rewardTokens, uint256[] calldata rewardAmounts, uint256 feeTarget ) external override isOperator checkLength(rewardTokens.length, rewardAmounts.length) { require(startTime >= _getBlockTime() && endTime > startTime, 'addPool: invalid times'); uint256 pId = poolLength; // save gas LMPoolInfo storage pool = pools[pId]; pool.poolAddress = poolAddress; pool.startTime = startTime; pool.endTime = endTime; pool.totalSecondsClaimed = 0; pool.feeTarget = feeTarget; for (uint256 i = 0; i < rewardTokens.length; i++) { pool.rewards.push(RewardData(rewardTokens[i], rewardAmounts[i])); } poolLength++; emit AddPool(pId, poolAddress, startTime, endTime, feeTarget); } /// @inheritdoc IKyberSwapElasticLM function renewPool( uint256 pId, uint32 startTime, uint32 endTime, uint256[] calldata rewardAmounts, uint256 feeTarget ) external override isOperator { LMPoolInfo storage pool = pools[pId]; // check if pool has not started or already ended require( pool.startTime > _getBlockTime() || pool.endTime < _getBlockTime(), 'renew: invalid pool state' ); require(pool.rewards.length == rewardAmounts.length, 'renew: invalid length'); // check input startTime and endTime require(startTime > _getBlockTime() && endTime > startTime, 'renew: invalid times'); // check pool has stakes require(pool.numStakes == 0, 'renew: pool has stakes'); pool.startTime = startTime; pool.endTime = endTime; pool.totalSecondsClaimed = 0; pool.feeTarget = feeTarget; for (uint256 i = 0; i < rewardAmounts.length; ++i) { pool.rewards[i].rewardUnclaimed = rewardAmounts[i]; } emit RenewPool(pId, startTime, endTime, feeTarget); } /// @inheritdoc IKyberSwapElasticLM function deposit(uint256[] calldata nftIds) external override nonReentrant { _depositAndJoin(0, nftIds, false); } /// @inheritdoc IKyberSwapElasticLM function depositAndJoin( uint256 pId, uint256[] calldata nftIds ) external override isSpecialFeaturesEnabled nonReentrant { _depositAndJoin(pId, nftIds, true); } /// @inheritdoc IKyberSwapElasticLM function withdraw(uint256[] calldata nftIds) external override nonReentrant { address sender = msg.sender; for (uint256 i = 0; i < nftIds.length; ++i) { require(positions[nftIds[i]].owner == sender, 'withdraw: not owner'); require(joinedPools[nftIds[i]].length() == 0, 'withdraw: not exited yet'); delete positions[nftIds[i]]; require(depositNFTs[sender].remove(nftIds[i])); nft.transferFrom(address(this), sender, nftIds[i]); emit Withdraw(sender, nftIds[i]); } } /// @inheritdoc IKyberSwapElasticLM function emergencyWithdraw(uint256[] calldata nftIds) external override nonReentrant { address sender = msg.sender; // save gas bool _emergencyEnabled = emergencyEnabled; for (uint256 i = 0; i < nftIds.length; ++i) { require(positions[nftIds[i]].owner == sender, 'withdraw: not owner'); isEmergencyWithdrawnNFT[nftIds[i]] = true; uint256[] memory values = joinedPools[nftIds[i]].values(); for (uint256 j = 0; j < values.length; ++j) { uint256 poolId = values[j]; unchecked { pools[poolId].numStakes--; } delete stakes[nftIds[i]][poolId]; } delete positions[nftIds[i]]; if (!_emergencyEnabled) { require(depositNFTs[sender].remove(nftIds[i])); for (uint256 j = 0; j < values.length; ++j) { uint256 poolId = values[j]; require(joinedPools[nftIds[i]].remove(poolId)); } } nft.transferFrom(address(this), sender, nftIds[i]); emit EmergencyWithdraw(sender, nftIds[i]); } } /// @inheritdoc IKyberSwapElasticLM function emergencyWithdrawForOwner( address[] calldata rewards, uint256[] calldata amounts ) external override isAdmin checkLength(rewards.length, amounts.length) { for (uint256 i = 0; i < rewards.length; ++i) { _transferReward(rewards[i], msg.sender, amounts[i]); emit EmergencyWithdrawForOwner(rewards[i], amounts[i]); } } /// @inheritdoc IKyberSwapElasticLM function join( uint256 pId, uint256[] calldata nftIds, uint256[] calldata liqs ) external override nonReentrant checkLength(nftIds.length, liqs.length) { require(poolLength > pId, 'Pool not exists'); LMPoolInfo storage pool = pools[pId]; require(pool.startTime <= _getBlockTime() && _getBlockTime() < pool.endTime, 'Invalid time'); for (uint256 i = 0; i < nftIds.length; ++i) { require(positions[nftIds[i]].owner == msg.sender, 'Not owner'); positions[nftIds[i]].liquidity = helper.getLiq(address(nft), nftIds[i]); StakeInfo storage stake = stakes[nftIds[i]][pId]; if (stake.liquidity == 0) { _join(nftIds[i], pId, liqs[i], pool); } else { _sync(nftIds[i], pId, liqs[i], pool); } } } /// @inheritdoc IKyberSwapElasticLM function exit( uint256 pId, uint256[] calldata nftIds, uint256[] calldata liqs ) external override nonReentrant checkLength(nftIds.length, liqs.length) { require(poolLength > pId, 'Pool not exists'); for (uint256 i = 0; i < nftIds.length; ++i) { _exit(nftIds[i], pId, liqs[i], true); } } /// @inheritdoc IKyberSwapElasticLM function harvestMultiplePools( uint256[] calldata nftIds, bytes[] calldata datas ) external override nonReentrant checkLength(nftIds.length, datas.length) { for (uint256 i; i < nftIds.length; ++i) { require(positions[nftIds[i]].owner == msg.sender, 'harvest: not owner'); HarvestData memory data = abi.decode(datas[i], (HarvestData)); for (uint256 j; j < data.pIds.length; ++j) { _harvest(nftIds[i], data.pIds[j]); } } } /// @inheritdoc IKyberSwapElasticLM function removeLiquidity( uint256 nftId, uint128 liquidity, uint256 amount0Min, uint256 amount1Min, uint256 deadline, bool isReceiveNative, bool[2] calldata claimFeeAndRewards ) external override nonReentrant isSpecialFeaturesEnabled { require(_getBlockTime() <= deadline, 'removeLiquidity: expired'); require(positions[nftId].owner == msg.sender, 'removeLiquidity: not owner'); uint256 posLiquidity = helper.getLiq(address(nft), nftId); require(liquidity > 0 && liquidity <= posLiquidity, 'removeLiquidity: invalid liquidity'); posLiquidity -= liquidity; positions[nftId].liquidity = posLiquidity; uint256[] memory poolIds = joinedPools[nftId].values(); for (uint256 i; i < poolIds.length; ) { uint256 stakedLiquidity = stakes[nftId][poolIds[i]].liquidity; uint256 deltaLiq = stakedLiquidity > posLiquidity ? stakedLiquidity - posLiquidity : 0; if (deltaLiq > 0) _exit(nftId, poolIds[i], deltaLiq, claimFeeAndRewards[1]); unchecked { ++i; } } (address token0, address token1) = helper.getPair(address(nft), nftId); _removeLiquidity(nftId, liquidity, deadline); if (claimFeeAndRewards[0]) _claimFee(nftId, deadline, false); _transferTokens(token0, token1, amount0Min, amount1Min, msg.sender, isReceiveNative); } /// @inheritdoc IKyberSwapElasticLM function claimFee( uint256[] calldata nftIds, uint256 amount0Min, uint256 amount1Min, address poolAddress, bool isReceiveNative, uint256 deadline ) external override nonReentrant isSpecialFeaturesEnabled { require(_getBlockTime() <= deadline, 'claimFee: expired'); uint256 length = nftIds.length; (address token0, address token1) = ( address(IPoolStorage(poolAddress).token0()), address(IPoolStorage(poolAddress).token1()) ); for (uint256 i; i < length; ) { require(positions[nftIds[i]].owner == msg.sender, 'claimFee: not owner'); (address nftToken0, address nftToken1) = helper.getPair(address(nft), nftIds[i]); require(nftToken0 == token0 && nftToken1 == token1, 'claimFee: token pair not match'); _claimFee(nftIds[i], deadline, true); unchecked { ++i; } } _transferTokens(token0, token1, amount0Min, amount1Min, msg.sender, isReceiveNative); } /// @inheritdoc IKyberSwapElasticLM function getJoinedPools( uint256 nftId ) external view override returns (uint256[] memory poolIds) { uint256 length = joinedPools[nftId].length(); poolIds = new uint256[](length); for (uint256 i = 0; i < length; ++i) { poolIds[i] = joinedPools[nftId].at(i); } } /// @inheritdoc IKyberSwapElasticLM function getJoinedPoolsInRange( uint256 nftId, uint256 fromIndex, uint256 toIndex ) external view returns (uint256[] memory poolIds) { require(fromIndex <= toIndex, 'fromIndex > toIndex'); require(toIndex < joinedPools[nftId].length(), 'toIndex >= length'); poolIds = new uint256[](toIndex - fromIndex + 1); for (uint256 index = fromIndex; index <= toIndex; ++index) { poolIds[index - fromIndex] = joinedPools[nftId].at(index); } } /// @inheritdoc IKyberSwapElasticLM function getUserInfo( uint256 nftId, uint256 pId ) external view override returns (uint256 liquidity, uint256[] memory rewardPending, uint256[] memory rewardLast) { LMPoolInfo storage pool = pools[pId]; StakeInfo storage stake = stakes[nftId][pId]; require(stake.liquidity > 0, 'getUserInfo: not joined yet'); rewardPending = new uint256[](pool.rewards.length); rewardLast = new uint256[](pool.rewards.length); RewardCalculationData memory data = getRewardCalculationData(nftId, pId); for (uint256 i = 0; i < pool.rewards.length; ++i) { uint256 rewardHarvest = _calculateRewardHarvest( stake.liquidity, pool.rewards[i].rewardUnclaimed, data.totalSecondsUnclaimed, data.secondsPerLiquidity ); uint256 rewardCollected = _calculateRewardCollected( stake.rewardHarvested[i] + rewardHarvest, data.vestingVolume, stake.rewardLast[i] ); rewardPending[i] = stake.rewardPending[i] + rewardCollected; rewardLast[i] = stake.rewardLast[i]; } liquidity = stake.liquidity; } /// @inheritdoc IKyberSwapElasticLM function getPoolInfo( uint256 pId ) external view override returns ( address poolAddress, uint32 startTime, uint32 endTime, uint256 totalSecondsClaimed, uint256 feeTarget, uint256 numStakes, //index reward => reward data address[] memory rewardTokens, uint256[] memory rewardUnclaimeds ) { LMPoolInfo storage pool = pools[pId]; poolAddress = pool.poolAddress; startTime = pool.startTime; endTime = pool.endTime; totalSecondsClaimed = pool.totalSecondsClaimed; feeTarget = pool.feeTarget; numStakes = pool.numStakes; uint256 length = pool.rewards.length; rewardTokens = new address[](length); rewardUnclaimeds = new uint256[](length); for (uint256 i = 0; i < length; ++i) { rewardTokens[i] = pool.rewards[i].rewardToken; rewardUnclaimeds[i] = pool.rewards[i].rewardUnclaimed; } } /// @inheritdoc IKyberSwapElasticLM function getDepositedNFTs(address user) external view returns (uint256[] memory listNFTs) { listNFTs = depositNFTs[user].values(); } /** * INTERNAL FUNCTIONS ************************* */ /** * @dev Deposit NFTs to the LM contract, and join farming pool if needed * @param pId pool id to join farm, if isJoining = true * @param nftIds list of NFT ids to deposit * @param isJoining whether to join farm with pId */ function _depositAndJoin(uint256 pId, uint256[] memory nftIds, bool isJoining) internal { require(!emergencyEnabled, 'Not allowed to deposit'); if (isJoining) { // verify if pool's state is valid require(poolLength > pId, 'Pool not exists'); uint32 _blockTime = _getBlockTime(); require( pools[pId].startTime <= _blockTime && _blockTime < pools[pId].endTime, 'Invalid time' ); } address sender = msg.sender; for (uint256 i = 0; i < nftIds.length; ) { // if the nft has used emergency withdraw before, not allow to re-deposit require(!isEmergencyWithdrawnNFT[nftIds[i]], 'Not allowed to deposit'); // and nft to the list and deposit nft to the LM contract require(depositNFTs[sender].add(nftIds[i])); nft.transferFrom(sender, address(this), nftIds[i]); emit Deposit(sender, nftIds[i]); // update position data positions[nftIds[i]].owner = sender; uint128 liquidity = helper.getLiq(address(nft), nftIds[i]); positions[nftIds[i]].liquidity = liquidity; // join full liquidity to the farm if joining is enabled if (isJoining) { _join(nftIds[i], pId, liquidity, pools[pId]); } unchecked { ++i; } } } /** * @dev join pool first time * @param nftId NFT id to join * @param pId pool id to join * @param liq liquidity amount to join * @param pool LM pool */ function _join(uint256 nftId, uint256 pId, uint256 liq, LMPoolInfo storage pool) internal { PositionInfo storage position = positions[nftId]; StakeInfo storage stake = stakes[nftId][pId]; require(helper.checkPool(pool.poolAddress, address(nft), nftId), 'join: invalid pool'); require(liq != 0 && liq <= position.liquidity, 'join: invalid liq'); stake.secondsPerLiquidityLast = helper.getActiveTime(pool.poolAddress, address(nft), nftId); stake.rewardLast = new uint256[](pool.rewards.length); stake.rewardPending = new uint256[](pool.rewards.length); stake.rewardHarvested = new uint256[](pool.rewards.length); if (pool.feeTarget != 0) { stake.feeFirst = helper.getSignedFee(address(nft), nftId); } stake.liquidity = liq; pool.numStakes++; require(joinedPools[nftId].add(pId), 'Fail to add joinedPools'); emit Join(nftId, pId, liq); } /** * @dev Increase liquidity in pool * @param nftId NFT id to sync * @param pId pool id to sync * @param liq liquidity amount to increase * @param pool LM pool */ function _sync(uint256 nftId, uint256 pId, uint256 liq, LMPoolInfo storage pool) internal { PositionInfo storage position = positions[nftId]; StakeInfo storage stake = stakes[nftId][pId]; require(liq != 0 && liq + stake.liquidity <= position.liquidity, 'sync: invalid liq'); RewardCalculationData memory data = getRewardCalculationData(nftId, pId); for (uint256 i = 0; i < pool.rewards.length; ++i) { uint256 rewardHarvest = _calculateRewardHarvest( stake.liquidity, pool.rewards[i].rewardUnclaimed, data.totalSecondsUnclaimed, data.secondsPerLiquidity ); if (rewardHarvest != 0) { stake.rewardHarvested[i] += rewardHarvest; pool.rewards[i].rewardUnclaimed -= rewardHarvest; } uint256 rewardCollected = _calculateRewardCollected( stake.rewardHarvested[i], data.vestingVolume, stake.rewardLast[i] ); if (rewardCollected != 0) { stake.rewardLast[i] += rewardCollected; stake.rewardPending[i] += rewardCollected; } } pool.totalSecondsClaimed += data.secondsClaim; stake.secondsPerLiquidityLast = data.secondsPerLiquidityNow; stake.feeFirst = _calculateFeeFirstAfterJoin( stake.feeFirst, data.feeNow, pool.feeTarget, stake.liquidity, liq, nftId ); stake.liquidity += liq; emit SyncLiq(nftId, pId, liq); } /** * @dev Exit pool * @param nftId NFT id to exit * @param pId pool id to exit * @param liq liquidity amount to exit * @param claimReward transfer reward or not */ function _exit(uint256 nftId, uint256 pId, uint256 liq, bool claimReward) internal { LMPoolInfo storage pool = pools[pId]; address pOwner = positions[nftId].owner; StakeInfo storage stake = stakes[nftId][pId]; require( pOwner == msg.sender || (_getBlockTime() > pool.endTime && operators[msg.sender]), 'exit: not owner or pool not ended' ); uint256 liquidityOld = stake.liquidity; require(liq != 0 && liq <= liquidityOld, 'exit: invalid liq'); uint256 liquidityNew = liquidityOld - liq; RewardCalculationData memory data = getRewardCalculationData(nftId, pId); pool.totalSecondsClaimed += data.secondsClaim; stake.secondsPerLiquidityLast = data.secondsPerLiquidityNow; stake.liquidity = liquidityNew; for (uint256 i = 0; i < pool.rewards.length; ++i) { uint256 rewardHarvest = _calculateRewardHarvest( liquidityOld, pool.rewards[i].rewardUnclaimed, data.totalSecondsUnclaimed, data.secondsPerLiquidity ); if (rewardHarvest != 0) { stake.rewardHarvested[i] += rewardHarvest; pool.rewards[i].rewardUnclaimed -= rewardHarvest; } uint256 rewardCollected = _calculateRewardCollected( stake.rewardHarvested[i], data.vestingVolume, stake.rewardLast[i] ); uint256 rewardPending = stake.rewardPending[i]; if (rewardCollected != 0) { stake.rewardLast[i] += rewardCollected; rewardPending += rewardCollected; } if (rewardPending != 0) { if (claimReward) { stake.rewardPending[i] = 0; _transferReward(pool.rewards[i].rewardToken, pOwner, rewardPending); emit Harvest(nftId, pOwner, pool.rewards[i].rewardToken, rewardPending); } else { stake.rewardPending[i] = rewardPending; } } } if (liquidityNew == 0) { delete stakes[nftId][pId]; pool.numStakes--; require(joinedPools[nftId].remove(pId), 'Fail to remove joinedPools'); } emit Exit(msg.sender, nftId, pId, liq); } /** * @dev Harvest reward * @param nftId NFT id to harvest * @param pId pool id to harvest */ function _harvest(uint256 nftId, uint256 pId) internal { require(poolLength > pId, 'Pool not exists'); LMPoolInfo storage pool = pools[pId]; address pOwner = positions[nftId].owner; StakeInfo storage stake = stakes[nftId][pId]; require(stake.liquidity > 0, 'harvest: not joined yet'); RewardCalculationData memory data = getRewardCalculationData(nftId, pId); pool.totalSecondsClaimed += data.secondsClaim; stake.secondsPerLiquidityLast = data.secondsPerLiquidityNow; for (uint256 i = 0; i < pool.rewards.length; ++i) { uint256 rewardHarvest = _calculateRewardHarvest( stake.liquidity, pool.rewards[i].rewardUnclaimed, data.totalSecondsUnclaimed, data.secondsPerLiquidity ); if (rewardHarvest != 0) { stake.rewardHarvested[i] += rewardHarvest; pool.rewards[i].rewardUnclaimed -= rewardHarvest; } uint256 rewardCollected = _calculateRewardCollected( stake.rewardHarvested[i], data.vestingVolume, stake.rewardLast[i] ); uint256 rewardPending = stake.rewardPending[i] + rewardCollected; if (rewardPending != 0) { if (rewardCollected != 0) { stake.rewardLast[i] += rewardCollected; } stake.rewardPending[i] = 0; _transferReward(pool.rewards[i].rewardToken, pOwner, rewardPending); emit Harvest(nftId, pOwner, pool.rewards[i].rewardToken, rewardPending); } } } /** * @dev transfer reward */ function _transferReward(address _token, address _account, uint256 _amount) internal { if (_token == address(0)) { (bool success, ) = payable(_account).call{value: _amount}(''); require(success, 'transfer reward token failed'); } else { IERC20Metadata(_token).safeTransfer(_account, _amount); } } /// @dev remove liquidiy of nft from posManager /// @param nftId nft's id /// @param liquidity liquidity amount to remove /// @param deadline removeLiquidity deadline function _removeLiquidity(uint256 nftId, uint128 liquidity, uint256 deadline) internal { IBasePositionManager.RemoveLiquidityParams memory removeLiq = IBasePositionManager .RemoveLiquidityParams({ tokenId: nftId, liquidity: liquidity, amount0Min: 0, amount1Min: 0, deadline: deadline }); IBasePositionManager(address(nft)).removeLiquidity(removeLiq); } /// @dev claim fee of nft from posManager /// @param nftId nft's id /// @param deadline claimFee deadline /// @param syncFee is need to sync new fee or not function _claimFee(uint256 nftId, uint256 deadline, bool syncFee) internal { if (syncFee) { IBasePositionManager(address(nft)).syncFeeGrowth(nftId); } IBasePositionManager.BurnRTokenParams memory burnRToken = IBasePositionManager .BurnRTokenParams({tokenId: nftId, amount0Min: 0, amount1Min: 0, deadline: deadline}); IBasePositionManager(address(nft)).burnRTokens(burnRToken); } /// @dev transfer tokens from removeLiquidity (and burnRToken if any) to receiver /// @param token0 address of token0 /// @param token1 address of token1 /// @param amount0Min minimum amount of token0 should receive /// @param amount1Min minimum amount of token1 should receive /// @param receiver receiver of tokens /// @param isReceiveNative should unwrap wrapped native or not function _transferTokens( address token0, address token1, uint256 amount0Min, uint256 amount1Min, address receiver, bool isReceiveNative ) internal { IBasePositionManager posManager = IBasePositionManager(address(nft)); if (isReceiveNative) { // expect to receive in native token if (weth == token0) { // receive in native for token0 posManager.unwrapWeth(amount0Min, receiver); posManager.transferAllTokens(token1, amount1Min, receiver); return; } if (weth == token1) { // receive in native for token1 posManager.transferAllTokens(token0, amount0Min, receiver); posManager.unwrapWeth(amount1Min, receiver); return; } } posManager.transferAllTokens(token0, amount0Min, receiver); posManager.transferAllTokens(token1, amount1Min, receiver); } /** * HELPER MATH FUNCTIONS ************************* */ function getRewardCalculationData( uint256 nftId, uint256 pId ) public view override returns (RewardCalculationData memory data) { LMPoolInfo storage pool = pools[pId]; StakeInfo storage stake = stakes[nftId][pId]; data.secondsPerLiquidityNow = helper.getActiveTime(pool.poolAddress, address(nft), nftId); data.feeNow = helper.getSignedFeePool(pool.poolAddress, address(nft), nftId); data.vestingVolume = _calculateVestingVolume(data.feeNow, stake.feeFirst, pool.feeTarget); data.totalSecondsUnclaimed = _calculateSecondsUnclaimed( pool.startTime, pool.endTime, pool.totalSecondsClaimed ); unchecked { data.secondsPerLiquidity = data.secondsPerLiquidityNow - stake.secondsPerLiquidityLast; } data.secondsClaim = stake.liquidity * data.secondsPerLiquidity; } /** * @dev feeFirst = (liq * max(feeNow - feeTarget, feeFirst) + liqAdd * feeNow) / liqNew */ function _calculateFeeFirstAfterJoin( int256 feeFirst, int256 feeNow, uint256 feeTarget, uint256 liquidity, uint256 liquidityAdd, uint256 nftId ) internal view returns (int256) { if (feeTarget == 0) { return 0; } int256 feeFirstCurrent = feeNow - int256(feeTarget) < feeFirst ? feeFirst : feeNow - int256(feeTarget); int256 numerator = int256(liquidity) * feeFirstCurrent + int256(liquidityAdd) * helper.getSignedFee(address(nft), nftId); int256 denominator = int256(liquidity + liquidityAdd); return numerator / denominator; } /** * @dev vesting = min((feeNow - feeFirst) / feeTarget, 1) */ function _calculateVestingVolume( int256 feeNow, int256 feeFirst, uint256 feeTarget ) internal pure returns (uint256) { if (feeTarget == 0) { return PRECISION; } uint256 feeInside = uint256(feeNow - feeFirst); return KSMath.min((feeInside * PRECISION) / feeTarget, PRECISION); } /** * @dev secondsUnclaimed = (max(currentTime, endTime) - startTime) - secondsClaimed */ function _calculateSecondsUnclaimed( uint256 startTime, uint256 endTime, uint256 totalSecondsClaimed ) internal view returns (uint256) { uint256 totalSeconds = KSMath.max(_getBlockTime(), endTime) - startTime; uint256 totalSecondsScaled = totalSeconds * (1 << 96); return totalSecondsScaled > totalSecondsClaimed ? totalSecondsScaled - totalSecondsClaimed : 0; } /** * @dev rewardHarvested = L * rewardRate * secondsPerLiquidity */ function _calculateRewardHarvest( uint256 liquidity, uint256 rewardUnclaimed, uint256 totalSecondsUnclaimed, uint256 secondsPerLiquidity ) internal pure returns (uint256) { return (liquidity * rewardUnclaimed * secondsPerLiquidity) / totalSecondsUnclaimed; } /** * @dev rewardCollected = Max(rewardHarvested * vestingVolume - rewardLast, 0); */ function _calculateRewardCollected( uint256 rewardHarvested, uint256 vestingVolume, uint256 rewardLast ) internal pure returns (uint256) { uint256 rewardNow = (rewardHarvested * vestingVolume) / PRECISION; return rewardNow > rewardLast ? rewardNow - rewardLast : 0; } function _getBlockTime() internal view virtual returns (uint32) { return uint32(block.timestamp); } }
// SPDX-License-Identifier: Unlicense pragma solidity ^0.8.0; library KSMath { function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? b : a; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {IKyberSwapElasticLMEvents} from './IKyberSwapElasticLMEvents.sol'; import {IERC721} from '@openzeppelin/contracts/token/ERC721/IERC721.sol'; interface IKyberSwapElasticLM is IKyberSwapElasticLMEvents { struct RewardData { address rewardToken; uint256 rewardUnclaimed; } struct LMPoolInfo { address poolAddress; uint32 startTime; uint32 endTime; uint256 totalSecondsClaimed; // scaled by (1 << 96) RewardData[] rewards; uint256 feeTarget; uint256 numStakes; } struct PositionInfo { address owner; uint256 liquidity; } struct StakeInfo { uint128 secondsPerLiquidityLast; uint256[] rewardLast; uint256[] rewardPending; uint256[] rewardHarvested; int256 feeFirst; uint256 liquidity; } // input data in harvestMultiplePools function struct HarvestData { uint256[] pIds; } // avoid stack too deep error struct RewardCalculationData { uint128 secondsPerLiquidityNow; int256 feeNow; uint256 vestingVolume; uint256 totalSecondsUnclaimed; uint256 secondsPerLiquidity; uint256 secondsClaim; // scaled by (1 << 96) } /** * @dev Add new pool to LM * @param poolAddr pool address * @param startTime start time of liquidity mining * @param endTime end time of liquidity mining * @param rewardTokens reward token list for pool * @param rewardAmounts reward amount of list token * @param feeTarget fee target for pool * */ function addPool( address poolAddr, uint32 startTime, uint32 endTime, address[] calldata rewardTokens, uint256[] calldata rewardAmounts, uint256 feeTarget ) external; /** * @dev Renew a pool to start another LM program * @param pId pool id to update * @param startTime start time of liquidity mining * @param endTime end time of liquidity mining * @param rewardAmounts reward amount of list token * @param feeTarget fee target for pool * */ function renewPool( uint256 pId, uint32 startTime, uint32 endTime, uint256[] calldata rewardAmounts, uint256 feeTarget ) external; /** * @dev Deposit NFT * @param nftIds list nft id * */ function deposit(uint256[] calldata nftIds) external; /** * @dev Deposit NFTs into the pool and join farms if applicable * @param pId pool id to join farm * @param nftIds List of NFT ids from BasePositionManager, should match with the pId * */ function depositAndJoin(uint256 pId, uint256[] calldata nftIds) external; /** * @dev Withdraw NFT, must exit all pool before call. * @param nftIds list nft id * */ function withdraw(uint256[] calldata nftIds) external; /** * @dev Join pools * @param pId pool id to join * @param nftIds nfts to join * @param liqs list liquidity value to join each nft * */ function join(uint256 pId, uint256[] calldata nftIds, uint256[] calldata liqs) external; /** * @dev Exit from pools * @param pId pool ids to exit * @param nftIds list nfts id * @param liqs list liquidity value to exit from each nft * */ function exit(uint256 pId, uint256[] calldata nftIds, uint256[] calldata liqs) external; /** * @dev Claim rewards for a list of pools for a list of nft positions * @param nftIds List of NFT ids to harvest * @param datas List of pool ids to harvest for each nftId, encoded into bytes */ function harvestMultiplePools(uint256[] calldata nftIds, bytes[] calldata datas) external; /** * @dev remove liquidity from elastic for a list of nft position, also update on farm * @param nftId to remove * @param liquidity liquidity amount to remove from nft * @param amount0Min expected min amount of token0 should receive * @param amount1Min expected min amount of token1 should receive * @param deadline deadline of this tx * @param isReceiveNative should unwrap native or not * @param claimFeeAndRewards also claim LP Fee and farm rewards */ function removeLiquidity( uint256 nftId, uint128 liquidity, uint256 amount0Min, uint256 amount1Min, uint256 deadline, bool isReceiveNative, bool[2] calldata claimFeeAndRewards ) external; /** * @dev Claim fee from elastic for a list of nft positions * @param nftIds List of NFT ids to claim * @param amount0Min expected min amount of token0 should receive * @param amount1Min expected min amount of token1 should receive * @param poolAddress address of Elastic pool of those nfts * @param isReceiveNative should unwrap native or not * @param deadline deadline of this tx */ function claimFee( uint256[] calldata nftIds, uint256 amount0Min, uint256 amount1Min, address poolAddress, bool isReceiveNative, uint256 deadline ) external; /** * @dev Operator only. Call to withdraw all reward from list pools. * @param rewards list reward address erc20 token * @param amounts amount to withdraw * */ function emergencyWithdrawForOwner( address[] calldata rewards, uint256[] calldata amounts ) external; /** * @dev Withdraw NFT, can call any time, reward will be reset. Must enable this func by operator * @param pIds list pool to withdraw * */ function emergencyWithdraw(uint256[] calldata pIds) external; /** * @dev get list of pool that this nft joined * @param nftId to get */ function getJoinedPools(uint256 nftId) external view returns (uint256[] memory poolIds); /** * @dev get list of pool that this nft joined, only in a specific range * @param nftId to get * @param fromIndex index from * @param toIndex index to */ function getJoinedPoolsInRange( uint256 nftId, uint256 fromIndex, uint256 toIndex ) external view returns (uint256[] memory poolIds); /** * @dev get user's info (staked info) of a nft in a pool * @param nftId to get * @param pId to get */ function getUserInfo( uint256 nftId, uint256 pId ) external view returns (uint256 liquidity, uint256[] memory rewardPending, uint256[] memory rewardLast); /** * @dev get pool info * @param pId to get */ function getPoolInfo( uint256 pId ) external view returns ( address poolAddress, uint32 startTime, uint32 endTime, uint256 totalSecondsClaimed, uint256 feeTarget, uint256 numStakes, //index reward => reward data address[] memory rewardTokens, uint256[] memory rewardUnclaimeds ); /** * @dev get list of deposited nfts of an address * @param user address of user to get */ function getDepositedNFTs(address user) external view returns (uint256[] memory listNFTs); function nft() external view returns (IERC721); function poolLength() external view returns (uint256); function getRewardCalculationData( uint256 nftId, uint256 pId ) external view returns (RewardCalculationData memory data); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IKSElasticLMHelper { function checkPool( address pAddress, address nftContract, uint256 nftId ) external view returns (bool); /// @dev use virtual to be overrided to mock data for fuzz tests function getActiveTime( address pAddr, address nftContract, uint256 nftId ) external view returns (uint128); function getSignedFee(address nftContract, uint256 nftId) external view returns (int256); function getSignedFeePool( address poolAddress, address nftContract, uint256 nftId ) external view returns (int256); function getLiq(address nftContract, uint256 nftId) external view returns (uint128); function getPair(address nftContract, uint256 nftId) external view returns (address, address); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; interface IBasePositionManager { struct Position { // the nonce for permits uint96 nonce; // the address that is approved for spending this token address operator; // the ID of the pool with which this token is connected uint80 poolId; // the tick range of the position int24 tickLower; int24 tickUpper; // the liquidity of the position uint128 liquidity; // the current rToken that the position owed uint256 rTokenOwed; // fee growth per unit of liquidity as of the last update to liquidity uint256 feeGrowthInsideLast; } struct PoolInfo { address token0; uint16 fee; address token1; } struct MintParams { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; int24[2] ticksPrevious; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; address recipient; uint256 deadline; } struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct RemoveLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct BurnRTokenParams { uint256 tokenId; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } function positions( uint256 tokenId ) external view returns (Position memory pos, PoolInfo memory info); function addressToPoolId(address pool) external view returns (uint80); function WETH() external view returns (address); function mint( MintParams calldata params ) external payable returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1); function addLiquidity( IncreaseLiquidityParams calldata params ) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1, uint256 additionalRTokenOwed); function removeLiquidity( RemoveLiquidityParams calldata params ) external returns (uint256 amount0, uint256 amount1, uint256 additionalRTokenOwed); function syncFeeGrowth(uint256 tokenId) external returns (uint256 additionalRTokenOwed); function burnRTokens( BurnRTokenParams calldata params ) external returns (uint256 rTokenQty, uint256 amount0, uint256 amount1); function transferAllTokens(address token, uint256 minAmount, address recipient) external payable; function unwrapWeth(uint256 minAmount, address recipient) external payable; }
// SPDX-License-Identifier: agpl-3.0 pragma solidity >=0.8.0; import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {IFactory} from './IFactory.sol'; interface IPoolStorage { struct PoolData { uint160 sqrtP; int24 nearestCurrentTick; int24 currentTick; bool locked; uint128 baseL; uint128 reinvestL; uint128 reinvestLLast; uint256 feeGrowthGlobal; uint128 secondsPerLiquidityGlobal; uint32 secondsPerLiquidityUpdateTime; } // data stored for each initialized individual tick struct TickData { // gross liquidity of all positions in tick uint128 liquidityGross; // liquidity quantity to be added | removed when tick is crossed up | down int128 liquidityNet; // fee growth per unit of liquidity on the other side of this tick (relative to current tick) // only has relative meaning, not absolute — the value depends on when the tick is initialized uint256 feeGrowthOutside; // seconds spent on the other side of this tick (relative to current tick) // only has relative meaning, not absolute — the value depends on when the tick is initialized uint128 secondsPerLiquidityOutside; } /// @notice The contract that deployed the pool, which must adhere to the IFactory interface /// @return The contract address function factory() external view returns (IFactory); /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (IERC20); /// @notice The second of the two tokens of the pool, sorted by address /// @return The token contract address function token1() external view returns (IERC20); /// @notice The fee to be charged for a swap in basis points /// @return The swap fee in basis points function swapFeeBps() external view returns (uint16); /// @notice The pool tick distance /// @dev Ticks can only be initialized and used at multiples of this value /// It remains an int24 to avoid casting even though it is >= 1. /// e.g: a tickDistance of 5 means ticks can be initialized every 5th tick, i.e., ..., -10, -5, 0, 5, 10, ... /// @return The tick distance function tickDistance() external view returns (int24); /// @notice Maximum gross liquidity that an initialized tick can have /// @dev This is to prevent overflow the pool's active base liquidity (uint128) /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool /// @return The max amount of liquidity per tick function maxTickLiquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross total liquidity amount from positions that uses this tick as a lower or upper tick /// liquidityNet how much liquidity changes when the pool tick crosses above the tick /// feeGrowthOutside the fee growth on the other side of the tick relative to the current tick /// secondsPerLiquidityOutside the seconds spent on the other side of the tick relative to the current tick function ticks(int24 tick) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside, uint128 secondsPerLiquidityOutside ); /// @notice Returns the previous and next initialized ticks of a specific tick /// @dev If specified tick is uninitialized, the returned values are zero. /// @param tick The tick to look up function initializedTicks(int24 tick) external view returns (int24 previous, int24 next); /// @notice Returns the information about a position by the position's key /// @return liquidity the liquidity quantity of the position /// @return feeGrowthInsideLast fee growth inside the tick range as of the last mint / burn action performed function getPositions( address owner, int24 tickLower, int24 tickUpper ) external view returns (uint128 liquidity, uint256 feeGrowthInsideLast); /// @notice Fetches the pool's prices, ticks and lock status /// @return sqrtP sqrt of current price: sqrt(token1/token0) /// @return currentTick pool's current tick /// @return nearestCurrentTick pool's nearest initialized tick that is <= currentTick /// @return locked true if pool is locked, false otherwise function getPoolState() external view returns ( uint160 sqrtP, int24 currentTick, int24 nearestCurrentTick, bool locked ); /// @notice Fetches the pool's liquidity values /// @return baseL pool's base liquidity without reinvest liqudity /// @return reinvestL the liquidity is reinvested into the pool /// @return reinvestLLast last cached value of reinvestL, used for calculating reinvestment token qty function getLiquidityState() external view returns ( uint128 baseL, uint128 reinvestL, uint128 reinvestLLast ); /// @return feeGrowthGlobal All-time fee growth per unit of liquidity of the pool function getFeeGrowthGlobal() external view returns (uint256); /// @return secondsPerLiquidityGlobal All-time seconds per unit of liquidity of the pool /// @return lastUpdateTime The timestamp in which secondsPerLiquidityGlobal was last updated function getSecondsPerLiquidityData() external view returns (uint128 secondsPerLiquidityGlobal, uint32 lastUpdateTime); /// @notice Calculates and returns the active time per unit of liquidity until current block.timestamp /// @param tickLower The lower tick (of a position) /// @param tickUpper The upper tick (of a position) /// @return secondsPerLiquidityInside active time (multiplied by 2^96) /// between the 2 ticks, per unit of liquidity. function getSecondsPerLiquidityInside(int24 tickLower, int24 tickUpper) external view returns (uint128 secondsPerLiquidityInside); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.9; abstract contract KSAdmin { address public admin; mapping(address => bool) public operators; // address => bool event TransferAdmin(address indexed admin); event UpdateOperator(address indexed user, bool grantOrRevoke); modifier isAdmin() { require(msg.sender == admin, 'forbidden'); _; } modifier isOperator() { require(operators[msg.sender], 'forbidden'); _; } constructor() { admin = msg.sender; operators[msg.sender] = true; } function transferAdmin(address _admin) external virtual isAdmin { require(_admin != address(0), 'forbidden'); admin = _admin; emit TransferAdmin(_admin); } function updateOperator(address user, bool grantOrRevoke) external isAdmin { operators[user] = grantOrRevoke; emit UpdateOperator(user, grantOrRevoke); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, 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"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // 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; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import {IKSElasticLMHelper} from './IKSElasticLMHelper.sol'; interface IKyberSwapElasticLMEvents { event AddPool( uint256 indexed pId, address poolAddress, uint32 startTime, uint32 endTime, uint256 feeTarget ); event RenewPool(uint256 indexed pid, uint32 startTime, uint32 endTime, uint256 feeTarget); event Deposit(address sender, uint256 indexed nftId); event Withdraw(address sender, uint256 indexed nftId); event Join(uint256 indexed nftId, uint256 indexed pId, uint256 indexed liq); event Exit(address to, uint256 indexed nftId, uint256 indexed pId, uint256 indexed liq); event SyncLiq(uint256 indexed nftId, uint256 indexed pId, uint256 indexed liq); event Harvest(uint256 indexed nftId, address to, address reward, uint256 indexed amount); event EmergencyEnabled(); event UpdateSpecialFeatureEnabled(bool enableOrDisable); event EmergencyWithdrawForOwner(address reward, uint256 indexed amount); event EmergencyWithdraw(address sender, uint256 indexed nftId); event LMHelperUpdated(IKSElasticLMHelper helper); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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 `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, 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 `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @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); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity >=0.8.0; /// @title KyberSwap v2 factory /// @notice Deploys KyberSwap v2 pools and manages control over government fees interface IFactory { /// @notice Emitted when a pool is created /// @param token0 First pool token by address sort order /// @param token1 Second pool token by address sort order /// @param swapFeeBps Fee to be collected upon every swap in the pool, in basis points /// @param tickDistance Minimum number of ticks between initialized ticks /// @param pool The address of the created pool event PoolCreated( address indexed token0, address indexed token1, uint16 indexed swapFeeBps, int24 tickDistance, address pool ); /// @notice Emitted when a new fee is enabled for pool creation via the factory /// @param swapFeeBps Fee to be collected upon every swap in the pool, in basis points /// @param tickDistance Minimum number of ticks between initialized ticks for pools created with the given fee event SwapFeeEnabled(uint16 indexed swapFeeBps, int24 indexed tickDistance); /// @notice Emitted when vesting period changes /// @param vestingPeriod The maximum time duration for which LP fees /// are proportionally burnt upon LP removals event VestingPeriodUpdated(uint32 vestingPeriod); /// @notice Emitted when configMaster changes /// @param oldConfigMaster configMaster before the update /// @param newConfigMaster configMaster after the update event ConfigMasterUpdated(address oldConfigMaster, address newConfigMaster); /// @notice Emitted when fee configuration changes /// @param feeTo Recipient of government fees /// @param governmentFeeBps Fee amount, in basis points, /// to be collected out of the fee charged for a pool swap event FeeConfigurationUpdated(address feeTo, uint16 governmentFeeBps); /// @notice Emitted when whitelist feature is enabled event WhitelistEnabled(); /// @notice Emitted when whitelist feature is disabled event WhitelistDisabled(); /// @notice Returns the maximum time duration for which LP fees /// are proportionally burnt upon LP removals function vestingPeriod() external view returns (uint32); /// @notice Returns the tick distance for a specified fee. /// @dev Once added, cannot be updated or removed. /// @param swapFeeBps Swap fee, in basis points. /// @return The tick distance. Returns 0 if fee has not been added. function feeAmountTickDistance(uint16 swapFeeBps) external view returns (int24); /// @notice Returns the address which can update the fee configuration function configMaster() external view returns (address); /// @notice Returns the keccak256 hash of the Pool creation code /// This is used for pre-computation of pool addresses function poolInitHash() external view returns (bytes32); /// @notice Fetches the recipient of government fees /// and current government fee charged in basis points function feeConfiguration() external view returns (address _feeTo, uint16 _governmentFeeBps); /// @notice Returns the status of whitelisting feature of NFT managers /// If true, anyone can mint liquidity tokens /// Otherwise, only whitelisted NFT manager(s) are allowed to mint liquidity tokens function whitelistDisabled() external view returns (bool); //// @notice Returns all whitelisted NFT managers /// If the whitelisting feature is turned on, /// only whitelisted NFT manager(s) are allowed to mint liquidity tokens function getWhitelistedNFTManagers() external view returns (address[] memory); /// @notice Checks if sender is a whitelisted NFT manager /// If the whitelisting feature is turned on, /// only whitelisted NFT manager(s) are allowed to mint liquidity tokens /// @param sender address to be checked /// @return true if sender is a whistelisted NFT manager, false otherwise function isWhitelistedNFTManager(address sender) external view returns (bool); /// @notice Returns the pool address for a given pair of tokens and a swap fee /// @dev Token order does not matter /// @param tokenA Contract address of either token0 or token1 /// @param tokenB Contract address of the other token /// @param swapFeeBps Fee to be collected upon every swap in the pool, in basis points /// @return pool The pool address. Returns null address if it does not exist function getPool( address tokenA, address tokenB, uint16 swapFeeBps ) external view returns (address pool); /// @notice Fetch parameters to be used for pool creation /// @dev Called by the pool constructor to fetch the parameters of the pool /// @return factory The factory address /// @return token0 First pool token by address sort order /// @return token1 Second pool token by address sort order /// @return swapFeeBps Fee to be collected upon every swap in the pool, in basis points /// @return tickDistance Minimum number of ticks between initialized ticks function parameters() external view returns ( address factory, address token0, address token1, uint16 swapFeeBps, int24 tickDistance ); /// @notice Creates a pool for the given two tokens and fee /// @param tokenA One of the two tokens in the desired pool /// @param tokenB The other of the two tokens in the desired pool /// @param swapFeeBps Desired swap fee for the pool, in basis points /// @dev Token order does not matter. tickDistance is determined from the fee. /// Call will revert under any of these conditions: /// 1) pool already exists /// 2) invalid swap fee /// 3) invalid token arguments /// @return pool The address of the newly created pool function createPool( address tokenA, address tokenB, uint16 swapFeeBps ) external returns (address pool); /// @notice Enables a fee amount with the given tickDistance /// @dev Fee amounts may never be removed once enabled /// @param swapFeeBps The fee amount to enable, in basis points /// @param tickDistance The distance between ticks to be enforced for all pools created with the given fee amount function enableSwapFee(uint16 swapFeeBps, int24 tickDistance) external; /// @notice Updates the address which can update the fee configuration /// @dev Must be called by the current configMaster function updateConfigMaster(address) external; /// @notice Updates the vesting period /// @dev Must be called by the current configMaster function updateVestingPeriod(uint32) external; /// @notice Updates the address receiving government fees and fee quantity /// @dev Only configMaster is able to perform the update /// @param feeTo Address to receive government fees collected from pools /// @param governmentFeeBps Fee amount, in basis points, /// to be collected out of the fee charged for a pool swap function updateFeeConfiguration(address feeTo, uint16 governmentFeeBps) external; /// @notice Enables the whitelisting feature /// @dev Only configMaster is able to perform the update function enableWhitelist() external; /// @notice Disables the whitelisting feature /// @dev Only configMaster is able to perform the update function disableWhitelist() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ 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 functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ 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"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ 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) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ 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) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason 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 { // 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 assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "none" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC721","name":"_nft","type":"address"},{"internalType":"contract IKSElasticLMHelper","name":"_helper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":false,"internalType":"address","name":"poolAddress","type":"address"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"AddPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdrawForOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"Exit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"reward","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"Join","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IKSElasticLMHelper","name":"helper","type":"address"}],"name":"LMHelperUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"startTime","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"endTime","type":"uint32"},{"indexed":false,"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"RenewPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"pId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"liq","type":"uint256"}],"name":"SyncLiq","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"}],"name":"TransferAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"bool","name":"grantOrRevoke","type":"bool"}],"name":"UpdateOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enableOrDisable","type":"bool"}],"name":"UpdateSpecialFeatureEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardAmounts","type":"uint256[]"},{"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"addPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"bool","name":"isReceiveNative","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"claimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"depositAndJoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyEnable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"rewards","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"emergencyWithdrawForOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liqs","type":"uint256[]"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getDepositedNFTs","outputs":[{"internalType":"uint256[]","name":"listNFTs","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getJoinedPools","outputs":[{"internalType":"uint256[]","name":"poolIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"fromIndex","type":"uint256"},{"internalType":"uint256","name":"toIndex","type":"uint256"}],"name":"getJoinedPoolsInRange","outputs":[{"internalType":"uint256[]","name":"poolIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"}],"name":"getPoolInfo","outputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"totalSecondsClaimed","type":"uint256"},{"internalType":"uint256","name":"feeTarget","type":"uint256"},{"internalType":"uint256","name":"numStakes","type":"uint256"},{"internalType":"address[]","name":"rewardTokens","type":"address[]"},{"internalType":"uint256[]","name":"rewardUnclaimeds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"pId","type":"uint256"}],"name":"getRewardCalculationData","outputs":[{"components":[{"internalType":"uint128","name":"secondsPerLiquidityNow","type":"uint128"},{"internalType":"int256","name":"feeNow","type":"int256"},{"internalType":"uint256","name":"vestingVolume","type":"uint256"},{"internalType":"uint256","name":"totalSecondsUnclaimed","type":"uint256"},{"internalType":"uint256","name":"secondsPerLiquidity","type":"uint256"},{"internalType":"uint256","name":"secondsClaim","type":"uint256"}],"internalType":"struct IKyberSwapElasticLM.RewardCalculationData","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint256","name":"pId","type":"uint256"}],"name":"getUserInfo","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256[]","name":"rewardPending","type":"uint256[]"},{"internalType":"uint256[]","name":"rewardLast","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"bytes[]","name":"datas","type":"bytes[]"}],"name":"harvestMultiplePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isEmergencyWithdrawnNFT","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"internalType":"uint256[]","name":"liqs","type":"uint256[]"}],"name":"join","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nft","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"operators","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"pools","outputs":[{"internalType":"address","name":"poolAddress","type":"address"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256","name":"totalSecondsClaimed","type":"uint256"},{"internalType":"uint256","name":"feeTarget","type":"uint256"},{"internalType":"uint256","name":"numStakes","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"positions","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"isReceiveNative","type":"bool"},{"internalType":"bool[2]","name":"claimFeeAndRewards","type":"bool[2]"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pId","type":"uint256"},{"internalType":"uint32","name":"startTime","type":"uint32"},{"internalType":"uint32","name":"endTime","type":"uint32"},{"internalType":"uint256[]","name":"rewardAmounts","type":"uint256[]"},{"internalType":"uint256","name":"feeTarget","type":"uint256"}],"name":"renewPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"specialFeatureEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"uint128","name":"secondsPerLiquidityLast","type":"uint128"},{"internalType":"int256","name":"feeFirst","type":"int256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"}],"name":"transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IKSElasticLMHelper","name":"_helper","type":"address"}],"name":"updateHelper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"grantOrRevoke","type":"bool"}],"name":"updateOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enableOrDisable","type":"bool"}],"name":"updateSpecialFeatureEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162005f7738038062005f77833981016040819052620000349162000125565b600160008181558154336001600160a01b031991821681178455825260026020908152604092839020805460ff19169094179093556001600160a01b038581166080819052600380549093169186169190911790915581516315ab88c960e31b81529151909263ad5c46489260048082019391829003018186803b158015620000bc57600080fd5b505afa158015620000d1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000f7919062000164565b6001600160a01b031660a052506200018b9050565b6001600160a01b03811681146200012257600080fd5b50565b600080604083850312156200013957600080fd5b825162000146816200010c565b602084015190925062000159816200010c565b809150509250929050565b6000602082840312156200017757600080fd5b815162000184816200010c565b9392505050565b60805160a051615d3a6200023d600039600081816102fa01528181614681015261478501526000818161038001528181610faf01528181611d2501528181612128015281816123d2015281816125fd01528181612a0301528181612e1801528181612eca01528181613355015281816134900152818161366001528181613c3301528181613d8a015281816144f5015281816145c901528181614650015281816149820152614b100152615d3a6000f3fe6080604052600436106101fd5760003560e01c806375829def1161010d578063b36b26c5116100a0578063c7ca58701161006f578063c7ca58701461074b578063d1941b061461076b578063dc168a921461078b578063e7762a0c146107ba578063f851a4401461082f57600080fd5b8063b36b26c5146106bc578063b63ff916146106dc578063b82562751461070c578063bb5ae7751461072c57600080fd5b806399fbab88116100dc57806399fbab881461052f578063ac4afa381461058e578063affe737914610631578063b221e5fd1461064657600080fd5b806375829def146104af5780638bcc4166146104cf57806391fb2f15146104ef578063983d95ce1461050f57600080fd5b806347ccca021161019057806361657b121161015f57806361657b121461040f57806366b5a6641461042f578063683f3eda1461044f5780636d44a3b21461046f578063705b5bef1461048f57600080fd5b806347ccca021461036e57806349b35168146103a257806350523cea146103cf578063598b8e71146103ef57600080fd5b80632f380b35116101cc5780632f380b35146102b45780633fc8cef3146102e857806341e817ab14610334578063430ccd9b1461035457600080fd5b8063078ded5d14610209578063081e3eda1461022b57806313e7c9d814610254578063180f80361461029457600080fd5b3661020457005b600080fd5b34801561021557600080fd5b5061022961022436600461515c565b61084f565b005b34801561023757600080fd5b5061024160045481565b6040519081526020015b60405180910390f35b34801561026057600080fd5b5061028461026f3660046151e7565b60026020526000908152604090205460ff1681565b604051901515815260200161024b565b3480156102a057600080fd5b506102296102af366004615204565b610b0b565b3480156102c057600080fd5b506102d46102cf36600461526f565b610c8d565b60405161024b9897969594939291906152c3565b3480156102f457600080fd5b5061031c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161024b565b34801561034057600080fd5b5061022961034f366004615363565b610e37565b34801561036057600080fd5b50600b546102849060ff1681565b34801561037a57600080fd5b5061031c7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103ae57600080fd5b506103c26103bd3660046153dc565b61118b565b60405161024b9190615408565b3480156103db57600080fd5b506102296103ea366004615429565b6112e3565b3480156103fb57600080fd5b5061022961040a366004615446565b611361565b34801561041b57600080fd5b5061022961042a366004615204565b6113d3565b34801561043b57600080fd5b5061022961044a366004615363565b611507565b34801561045b57600080fd5b5061022961046a366004615487565b6115d8565b34801561047b57600080fd5b5061022961048a3660046154d2565b611674565b34801561049b57600080fd5b506103c26104aa36600461526f565b6116fd565b3480156104bb57600080fd5b506102296104ca3660046151e7565b6117b5565b3480156104db57600080fd5b506102296104ea3660046151e7565b61184f565b3480156104fb57600080fd5b5061022961050a36600461550b565b6118c7565b34801561051b57600080fd5b5061022961052a366004615446565b611b60565b34801561053b57600080fd5b5061056f61054a36600461526f565b600660205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161024b565b34801561059a57600080fd5b506105f06105a936600461526f565b60056020526000908152604090208054600182015460038301546004909301546001600160a01b0383169363ffffffff600160a01b8504811694600160c01b900416929186565b604080516001600160a01b0397909716875263ffffffff958616602088015293909416928501929092526060840152608083015260a082015260c00161024b565b34801561063d57600080fd5b50610229611e30565b34801561065257600080fd5b506106976106613660046155b5565b60076020908152600092835260408084209091529082529020805460048201546005909201546001600160801b03909116919083565b604080516001600160801b03909416845260208401929092529082015260600161024b565b3480156106c857600080fd5b506103c26106d73660046151e7565b611ed5565b3480156106e857600080fd5b506102846106f736600461526f565b600a6020526000908152604090205460ff1681565b34801561071857600080fd5b506102296107273660046155d7565b611eff565b34801561073857600080fd5b50600b5461028490610100900460ff1681565b34801561075757600080fd5b50610229610766366004615672565b6122ad565b34801561077757600080fd5b50610229610786366004615446565b6126d6565b34801561079757600080fd5b506107ab6107a63660046155b5565b612b10565b60405161024b939291906156ea565b3480156107c657600080fd5b506107da6107d53660046155b5565b612d81565b60405161024b9190600060c0820190506001600160801b0383511682526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b34801561083b57600080fd5b5060015461031c906001600160a01b031681565b3360009081526002602052604090205460ff166108875760405162461bcd60e51b815260040161087e90615715565b60405180910390fd5b6000868152600560205260409020805463ffffffff428116600160a01b9092041611806108c45750805463ffffffff428116600160c01b90920416105b6109105760405162461bcd60e51b815260206004820152601960248201527f72656e65773a20696e76616c696420706f6f6c20737461746500000000000000604482015260640161087e565b6002810154831461095b5760405162461bcd60e51b81526020600482015260156024820152740e4cadccaee7440d2dcecc2d8d2c840d8cadccee8d605b1b604482015260640161087e565b4263ffffffff168663ffffffff1611801561098157508563ffffffff168563ffffffff16115b6109c45760405162461bcd60e51b815260206004820152601460248201527372656e65773a20696e76616c69642074696d657360601b604482015260640161087e565b600481015415610a0f5760405162461bcd60e51b815260206004820152601660248201527572656e65773a20706f6f6c20686173207374616b657360501b604482015260640161087e565b805463ffffffff868116600160c01b0263ffffffff60c01b19918916600160a01b029190911667ffffffffffffffff60a01b1990921691909117178155600060018201819055600382018390555b83811015610ab757848482818110610a7757610a77615738565b90506020020135826002018281548110610a9357610a93615738565b6000918252602090912060016002909202010155610ab081615764565b9050610a5d565b506040805163ffffffff80891682528716602082015290810183905287907feda7bcc7e20158ff9fa87a4200758e927bbb3c8823e648403bdd6053b96dd0ad9060600160405180910390a250505050505050565b60026000541415610b2e5760405162461bcd60e51b815260040161087e9061577f565b60026000558281808214610b545760405162461bcd60e51b815260040161087e906157b6565b60005b85811015610c7f573360066000898985818110610b7657610b76615738565b60209081029290920135835250810191909152604001600020546001600160a01b031614610bdb5760405162461bcd60e51b81526020600482015260126024820152713430b93b32b9ba1d103737ba1037bbb732b960711b604482015260640161087e565b6000858583818110610bef57610bef615738565b9050602002810190610c0191906157de565b810190610c0e9190615892565b905060005b815151811015610c6c57610c5c898985818110610c3257610c32615738565b9050602002013583600001518381518110610c4f57610c4f615738565b6020026020010151612fc9565b610c6581615764565b9050610c13565b505080610c7890615764565b9050610b57565b505060016000555050505050565b6000818152600560205260409020805460018201546003830154600484015460028501546001600160a01b0385169563ffffffff600160a01b8704811696600160c01b900416949392916060918291806001600160401b03811115610cf457610cf4615824565b604051908082528060200260200182016040528015610d1d578160200160208202803683370190505b509350806001600160401b03811115610d3857610d38615824565b604051908082528060200260200182016040528015610d61578160200160208202803683370190505b50925060005b81811015610e2957826002018181548110610d8457610d84615738565b600091825260209091206002909102015485516001600160a01b0390911690869083908110610db557610db5615738565b60200260200101906001600160a01b031690816001600160a01b031681525050826002018181548110610dea57610dea615738565b906000526020600020906002020160010154848281518110610e0e57610e0e615738565b6020908102919091010152610e2281615764565b9050610d67565b505050919395975091939597565b60026000541415610e5a5760405162461bcd60e51b815260040161087e9061577f565b60026000558281808214610e805760405162461bcd60e51b815260040161087e906157b6565b8660045411610ea15760405162461bcd60e51b815260040161087e90615966565b6000878152600560205260409020805463ffffffff428116600160a01b9092041611801590610ee357508054600160c01b900463ffffffff164263ffffffff16105b610f1e5760405162461bcd60e51b815260206004820152600c60248201526b496e76616c69642074696d6560a01b604482015260640161087e565b60005b8681101561117b5733600660008a8a85818110610f4057610f40615738565b60209081029290920135835250810191909152604001600020546001600160a01b031614610f9c5760405162461bcd60e51b81526020600482015260096024820152682737ba1037bbb732b960b91b604482015260640161087e565b6003546001600160a01b0316635c6d96a97f00000000000000000000000000000000000000000000000000000000000000008a8a85818110610fe057610fe0615738565b6040516001600160e01b031960e087901b1681526001600160a01b039094166004850152602002919091013560248301525060440160206040518083038186803b15801561102d57600080fd5b505afa158015611041573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611065919061598f565b6001600160801b0316600660008a8a8581811061108457611084615738565b905060200201358152602001908152602001600020600101819055506000600760008a8a858181106110b8576110b8615738565b90506020020135815260200190815260200160002060008b8152602001908152602001600020905080600501546000141561112e5761112989898481811061110257611102615738565b905060200201358b89898681811061111c5761111c615738565b9050602002013586613303565b61116a565b61116a89898481811061114357611143615738565b905060200201358b89898681811061115d5761115d615738565b90506020020135866137a9565b5061117481615764565b9050610f21565b5050600160005550505050505050565b6060818311156111d35760405162461bcd60e51b81526020600482015260136024820152720cce4deda92dcc8caf0407c40e8de92dcc8caf606b1b604482015260640161087e565b60008481526008602052604090206111ea90613a36565b821061122c5760405162461bcd60e51b81526020600482015260116024820152700e8de92dcc8caf0407c7a40d8cadccee8d607b1b604482015260640161087e565b61123683836159ac565b6112419060016159c3565b6001600160401b0381111561125857611258615824565b604051908082528060200260200182016040528015611281578160200160208202803683370190505b509050825b8281116112db5760008581526008602052604090206112a59082613a40565b826112b086846159ac565b815181106112c0576112c0615738565b60209081029190910101526112d481615764565b9050611286565b509392505050565b6001546001600160a01b0316331461130d5760405162461bcd60e51b815260040161087e90615715565b600b80548215156101000261ff00199091161790556040517f294aa6bf970997b8c55a069e787eae16138f63ad315362696337d14ef42281ea9061135690831515815260200190565b60405180910390a150565b600260005414156113845760405162461bcd60e51b815260040161087e9061577f565b60026000819055506113ca600083838080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509250613a53915050565b50506001600055565b6001546001600160a01b031633146113fd5760405162461bcd60e51b815260040161087e90615715565b828180821461141e5760405162461bcd60e51b815260040161087e906157b6565b60005b858110156114fe5761147287878381811061143e5761143e615738565b905060200201602081019061145391906151e7565b3387878581811061146657611466615738565b90506020020135613eda565b84848281811061148457611484615738565b905060200201357f4042b7789d1f6c4d5a798b447cfb918e82b64dd68b81d78ddc4dd1944ba5c51c8888848181106114be576114be615738565b90506020020160208101906114d391906151e7565b6040516001600160a01b03909116815260200160405180910390a26114f781615764565b9050611421565b50505050505050565b6002600054141561152a5760405162461bcd60e51b815260040161087e9061577f565b600260005582818082146115505760405162461bcd60e51b815260040161087e906157b6565b86600454116115715760405162461bcd60e51b815260040161087e90615966565b60005b858110156115c9576115b987878381811061159157611591615738565b90506020020135898787858181106115ab576115ab615738565b905060200201356001613faa565b6115c281615764565b9050611574565b50506001600055505050505050565b600b54610100900460ff166115ff5760405162461bcd60e51b815260040161087e906159db565b600260005414156116225760405162461bcd60e51b815260040161087e9061577f565b600260008190555061166a8383838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525060019250613a53915050565b5050600160005550565b6001546001600160a01b0316331461169e5760405162461bcd60e51b815260040161087e90615715565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915591519182527f2ee52be9d342458b3d25e07faada7ff9bc06723b4aa24edb6321ac1316b8a9dd910160405180910390a25050565b60008181526008602052604081206060919061171890613a36565b9050806001600160401b0381111561173257611732615824565b60405190808252806020026020018201604052801561175b578160200160208202803683370190505b50915060005b818110156117ae5760008481526008602052604090206117819082613a40565b83828151811061179357611793615738565b60209081029190910101526117a781615764565b9050611761565b5050919050565b6001546001600160a01b031633146117df5760405162461bcd60e51b815260040161087e90615715565b6001600160a01b0381166118055760405162461bcd60e51b815260040161087e90615715565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fda7b0a7bc965abdec8a1a995575a891838264c2968e14bd456c5391827b7aa3090600090a250565b6001546001600160a01b031633146118795760405162461bcd60e51b815260040161087e90615715565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f7b9adf13852d5b3e153f2a442b9aa3a4570da8f9b9046c60410b17e8034fe33c90602001611356565b3360009081526002602052604090205460ff166118f65760405162461bcd60e51b815260040161087e90615715565b83828082146119175760405162461bcd60e51b815260040161087e906157b6565b4263ffffffff168963ffffffff161015801561193e57508863ffffffff168863ffffffff16115b6119835760405162461bcd60e51b8152602060048201526016602482015275616464506f6f6c3a20696e76616c69642074696d657360501b604482015260640161087e565b6000600454905060006005600083815260200190815260200160002090508b8160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508a8160000160146101000a81548163ffffffff021916908363ffffffff160217905550898160000160186101000a81548163ffffffff021916908363ffffffff1602179055506000816001018190555084816003018190555060005b88811015611ae3578160020160405180604001604052808c8c85818110611a4f57611a4f615738565b9050602002016020810190611a6491906151e7565b6001600160a01b031681526020018a8a85818110611a8457611a84615738565b60209081029290920135909252835460018082018655600095865294829020845160029092020180546001600160a01b0319166001600160a01b0390921691909117815592015191909201555080611adb81615764565b915050611a26565b5060048054906000611af483615764565b9091555050604080516001600160a01b038e16815263ffffffff8d811660208301528c168183015260608101879052905183917f251199ba7b3e7a12b779b3f606eaf369cecc0eac8bcbacaadcf08079e8c5940f919081900360800190a2505050505050505050505050565b60026000541415611b835760405162461bcd60e51b815260040161087e9061577f565b6002600090815533905b82811015611e2557816001600160a01b031660066000868685818110611bb557611bb5615738565b60209081029290920135835250810191909152604001600020546001600160a01b031614611c1b5760405162461bcd60e51b81526020600482015260136024820152723bb4ba34323930bb9d103737ba1037bbb732b960691b604482015260640161087e565b611c4e60086000868685818110611c3457611c34615738565b905060200201358152602001908152602001600020613a36565b15611c9b5760405162461bcd60e51b815260206004820152601860248201527f77697468647261773a206e6f7420657869746564207965740000000000000000604482015260640161087e565b60066000858584818110611cb157611cb1615738565b60209081029290920135835250810191909152604001600090812080546001600160a01b031916815560010155611d1a848483818110611cf357611cf3615738565b6001600160a01b0386166000908152600960209081526040909120939102013590506144c0565b611d2357600080fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd3084878786818110611d6657611d66615738565b905060200201356040518463ffffffff1660e01b8152600401611d8b93929190615a12565b600060405180830381600087803b158015611da557600080fd5b505af1158015611db9573d6000803e3d6000fd5b50505050838382818110611dcf57611dcf615738565b6040516001600160a01b038616815260209182029390930135927f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436492500160405180910390a2611e1e81615764565b9050611b8d565b505060016000555050565b6001546001600160a01b03163314611e5a5760405162461bcd60e51b815260040161087e90615715565b600b5460ff1615611e9d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b604482015260640161087e565b600b805460ff191660011790556040517f1d8c7af3ae0426053ea40080543aa1cbe5bea5cdb7a55888b4cca96eea0493e490600090a1565b6001600160a01b0381166000908152600960205260409020606090611ef9906144cc565b92915050565b60026000541415611f225760405162461bcd60e51b815260040161087e9061577f565b6002600055600b54610100900460ff16611f4e5760405162461bcd60e51b815260040161087e906159db565b804263ffffffff161115611f985760405162461bcd60e51b815260206004820152601160248201527018db185a5b5199594e88195e1c1a5c9959607a1b604482015260640161087e565b6000878790509050600080856001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015611fdc57600080fd5b505afa158015611ff0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120149190615a36565b866001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561204d57600080fd5b505afa158015612061573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120859190615a36565b9150915060005b8381101561228d5733600660008d8d858181106120ab576120ab615738565b60209081029290920135835250810191909152604001600020546001600160a01b0316146121115760405162461bcd60e51b815260206004820152601360248201527231b630b4b6a332b29d103737ba1037bbb732b960691b604482015260640161087e565b60035460009081906001600160a01b0316626349fb7f00000000000000000000000000000000000000000000000000000000000000008f8f8781811061215957612159615738565b6040516001600160e01b031960e087901b1681526001600160a01b0390941660048501526020029190910135602483015250604401604080518083038186803b1580156121a557600080fd5b505afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121dd9190615a53565b91509150846001600160a01b0316826001600160a01b03161480156122135750836001600160a01b0316816001600160a01b0316145b61225f5760405162461bcd60e51b815260206004820152601e60248201527f636c61696d4665653a20746f6b656e2070616972206e6f74206d617463680000604482015260640161087e565b6122838d8d8581811061227457612274615738565b905060200201358860016144d9565b505060010161208c565b5061229c82828a8a338a61464e565b505060016000555050505050505050565b600260005414156122d05760405162461bcd60e51b815260040161087e9061577f565b6002600055600b54610100900460ff166122fc5760405162461bcd60e51b815260040161087e906159db565b824263ffffffff1611156123525760405162461bcd60e51b815260206004820152601860248201527f72656d6f76654c69717569646974793a20657870697265640000000000000000604482015260640161087e565b6000878152600660205260409020546001600160a01b031633146123b85760405162461bcd60e51b815260206004820152601a60248201527f72656d6f76654c69717569646974793a206e6f74206f776e6572000000000000604482015260640161087e565b600354604051635c6d96a960e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018a90526000921690635c6d96a99060440160206040518083038186803b15801561242557600080fd5b505afa158015612439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245d919061598f565b6001600160801b031690506000876001600160801b031611801561248a575080876001600160801b031611155b6124e15760405162461bcd60e51b815260206004820152602260248201527f72656d6f76654c69717569646974793a20696e76616c6964206c697175696469604482015261747960f01b606482015260840161087e565b6124f46001600160801b038816826159ac565b6000898152600660209081526040808320600101849055600890915281209192509061251f906144cc565b905060005b81518110156125e35760008a81526007602052604081208351829085908590811061255157612551615738565b60200260200101518152602001908152602001600020600501549050600084821161257d576000612587565b61258785836159ac565b905080156125d9576125d98c8585815181106125a5576125a5615738565b602002602001015183896001600281106125c1576125c1615738565b6020020160208101906125d49190615429565b613faa565b5050600101612524565b50600354604051626349fb60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018c90526000928392911690626349fb90604401604080518083038186803b15801561265157600080fd5b505afa158015612665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126899190615a53565b915091506126988b8b89614918565b6126a56020860186615429565b156126b6576126b68b8860006144d9565b6126c482828b8b338b61464e565b50506001600055505050505050505050565b600260005414156126f95760405162461bcd60e51b815260040161087e9061577f565b60026000908155600b54339160ff909116905b83811015612b0457826001600160a01b03166006600087878581811061273457612734615738565b60209081029290920135835250810191909152604001600020546001600160a01b03161461279a5760405162461bcd60e51b81526020600482015260136024820152723bb4ba34323930bb9d103737ba1037bbb732b960691b604482015260640161087e565b6001600a60008787858181106127b2576127b2615738565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055506000612813600860008888868181106127f9576127f9615738565b9050602002013581526020019081526020016000206144cc565b905060005b81518110156128f057600082828151811061283557612835615738565b60209081029190910181015160008181526005909252604082206004018054600019019055915060079089898781811061287157612871615738565b602090810292909201358352508181019290925260409081016000908120848252909252812080546001600160801b0319168155906128b36001830182615077565b6128c1600283016000615077565b6128cf600383016000615077565b50600060048201819055600590910155506128e981615764565b9050612818565b506006600087878581811061290757612907615738565b60209081029290920135835250810191909152604001600090812080546001600160a01b03191681556001015582612a015761297586868481811061294e5761294e615738565b6001600160a01b0388166000908152600960209081526040909120939102013590506144c0565b61297e57600080fd5b60005b81518110156129ff57600082828151811061299e5761299e615738565b602002602001015190506129e581600860008b8b898181106129c2576129c2615738565b9050602002013581526020019081526020016000206144c090919063ffffffff16565b6129ee57600080fd5b506129f881615764565b9050612981565b505b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd3086898987818110612a4457612a44615738565b905060200201356040518463ffffffff1660e01b8152600401612a6993929190615a12565b600060405180830381600087803b158015612a8357600080fd5b505af1158015612a97573d6000803e3d6000fd5b50505050858583818110612aad57612aad615738565b6040516001600160a01b038816815260209182029390930135927f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd969592500160405180910390a250612afd81615764565b905061270c565b50506001600055505050565b600081815260056020818152604080842086855260078352818520868652909252832091820154606092839291612b895760405162461bcd60e51b815260206004820152601b60248201527f67657455736572496e666f3a206e6f74206a6f696e6564207965740000000000604482015260640161087e565b60028201546001600160401b03811115612ba557612ba5615824565b604051908082528060200260200182016040528015612bce578160200160208202803683370190505b5060028301549094506001600160401b03811115612bee57612bee615824565b604051908082528060200260200182016040528015612c17578160200160208202803683370190505b5092506000612c268888612d81565b905060005b6002840154811015612d6f576000612c778460050154866002018481548110612c5657612c56615738565b906000526020600020906002020160010154856060015186608001516149b9565b90506000612cd382866003018581548110612c9457612c94615738565b9060005260206000200154612ca991906159c3565b8560400151876001018681548110612cc357612cc3615738565b90600052602060002001546149e4565b905080856002018481548110612ceb57612ceb615738565b9060005260206000200154612d0091906159c3565b888481518110612d1257612d12615738565b602002602001018181525050846001018381548110612d3357612d33615738565b9060005260206000200154878481518110612d5057612d50615738565b602002602001018181525050505080612d6890615764565b9050612c2b565b50816005015495505050509250925092565b612dc36040518060c0016040528060006001600160801b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000828152600560209081526040808320868452600783528184208685529092529182902060035482549351632106297960e11b8152929391926001600160a01b039182169263420c52f292612e42929116907f0000000000000000000000000000000000000000000000000000000000000000908a90600401615a12565b60206040518083038186803b158015612e5a57600080fd5b505afa158015612e6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e92919061598f565b6001600160801b0316835260035482546040516339bb866b60e11b81526001600160a01b03928316926373770cd692612ef4929116907f0000000000000000000000000000000000000000000000000000000000000000908a90600401615a12565b60206040518083038186803b158015612f0c57600080fd5b505afa158015612f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f449190615a82565b6020840181905260048201546003840154612f60929190614a1b565b604084015281546001830154612f8e9163ffffffff600160a01b8204811692600160c01b9092041690614a64565b6060840152805483516001600160801b03918216900316608084018190526005820154612fbb9190615a9b565b60a084015250909392505050565b8060045411612fea5760405162461bcd60e51b815260040161087e90615966565b60008181526005602081815260408084208685526006835281852054600784528286208787529093529320918201546001600160a01b0390911691906130725760405162461bcd60e51b815260206004820152601760248201527f686172766573743a206e6f74206a6f696e656420796574000000000000000000604482015260640161087e565b600061307e8686612d81565b90508060a0015184600101600082825461309891906159c3565b9091555050805182546001600160801b0319166001600160801b0390911617825560005b60028501548110156114fe5760006130e78460050154876002018481548110612c5657612c56615738565b90508015613161578084600301838154811061310557613105615738565b90600052602060002001600082825461311e91906159c3565b925050819055508086600201838154811061313b5761313b615738565b9060005260206000209060020201600101600082825461315b91906159ac565b90915550505b60006131a085600301848154811061317b5761317b615738565b90600052602060002001548560400151876001018681548110612cc357612cc3615738565b90506000818660020185815481106131ba576131ba615738565b90600052602060002001546131cf91906159c3565b905080156132ef57811561321257818660010185815481106131f3576131f3615738565b90600052602060002001600082825461320c91906159c3565b90915550505b600086600201858154811061322957613229615738565b906000526020600020018190555061327088600201858154811061324f5761324f615738565b60009182526020909120600290910201546001600160a01b03168883613eda565b808a7f1ec92956b13869de207e232e60c65e35826c5e12b7fdc6d70b083b5a4fd26703898b60020188815481106132a9576132a9615738565b60009182526020909120600290910201546040516132e692916001600160a01b0316906001600160a01b0392831681529116602082015260400190565b60405180910390a35b505050806132fc90615764565b90506130bc565b600084815260066020908152604080832060078352818420878552909252918290206003548454935163d7aee3bd60e01b8152929391926001600160a01b039182169263d7aee3bd9261337f929116907f0000000000000000000000000000000000000000000000000000000000000000908b90600401615a12565b60206040518083038186803b15801561339757600080fd5b505afa1580156133ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cf9190615aba565b6134105760405162461bcd60e51b81526020600482015260126024820152711a9bda5b8e881a5b9d985b1a59081c1bdbdb60721b604482015260640161087e565b8315801590613423575081600101548411155b6134635760405162461bcd60e51b81526020600482015260116024820152706a6f696e3a20696e76616c6964206c697160781b604482015260640161087e565b6003548354604051632106297960e11b81526001600160a01b039283169263420c52f2926134ba929116907f0000000000000000000000000000000000000000000000000000000000000000908b90600401615a12565b60206040518083038186803b1580156134d257600080fd5b505afa1580156134e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350a919061598f565b81546001600160801b0319166001600160801b039190911617815560028301546001600160401b0381111561354157613541615824565b60405190808252806020026020018201604052801561356a578160200160208202803683370190505b508051613581916001840191602090910190615098565b5060028301546001600160401b0381111561359e5761359e615824565b6040519080825280602002602001820160405280156135c7578160200160208202803683370190505b5080516135de916002840191602090910190615098565b5060028301546001600160401b038111156135fb576135fb615824565b604051908082528060200260200182016040528015613624578160200160208202803683370190505b50805161363b916003840191602090910190615098565b506003830154156136f05760035460405163528ee47960e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018990529091169063a51dc8f29060440160206040518083038186803b1580156136b257600080fd5b505afa1580156136c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136ea9190615a82565b60048201555b6005810184905560048301805490600061370983615764565b909155505060008681526008602052604090206137269086614ab8565b6137725760405162461bcd60e51b815260206004820152601760248201527f4661696c20746f20616464206a6f696e6564506f6f6c73000000000000000000604482015260640161087e565b8385877f5d48292d83151281e6ea967de9fd35716c713dc76c11beb42d78ed5110270f7360405160405180910390a4505050505050565b60008481526006602090815260408083206007835281842087855290925290912083158015906137eb5750600182015460058201546137e890866159c3565b11155b61382b5760405162461bcd60e51b815260206004820152601160248201527073796e633a20696e76616c6964206c697160781b604482015260640161087e565b60006138378787612d81565b905060005b60028501548110156139815760006138678460050154876002018481548110612c5657612c56615738565b905080156138e1578084600301838154811061388557613885615738565b90600052602060002001600082825461389e91906159c3565b92505081905550808660020183815481106138bb576138bb615738565b906000526020600020906002020160010160008282546138db91906159ac565b90915550505b60006138fb85600301848154811061317b5761317b615738565b9050801561396e578085600101848154811061391957613919615738565b90600052602060002001600082825461393291906159c3565b925050819055508085600201848154811061394f5761394f615738565b90600052602060002001600082825461396891906159c3565b90915550505b50508061397a90615764565b905061383c565b508060a0015184600101600082825461399a91906159c3565b9091555050805182546001600160801b0319166001600160801b0390911617825560048201546020820151600386015460058501546139dd93929190898c614ac4565b8260040181905550848260050160008282546139f991906159c3565b90915550506040518590879089907ff31cd5db84a4ab16cd339c510d5a60c63ef5818c538aa67046f5bc0dca794cd390600090a450505050505050565b6000611ef9825490565b6000613a4c8383614be6565b9392505050565b600b5460ff1615613a9f5760405162461bcd60e51b8152602060048201526016602482015275139bdd08185b1b1bddd959081d1bc819195c1bdcda5d60521b604482015260640161087e565b8015613b51578260045411613ac65760405162461bcd60e51b815260040161087e90615966565b600083815260056020526040902054429063ffffffff808316600160a01b9092041611801590613b14575060008481526005602052604090205463ffffffff600160c01b9091048116908216105b613b4f5760405162461bcd60e51b815260206004820152600c60248201526b496e76616c69642074696d6560a01b604482015260640161087e565b505b3360005b8351811015613ed357600a6000858381518110613b7457613b74615738565b60209081029190910181015182528101919091526040016000205460ff1615613bd85760405162461bcd60e51b8152602060048201526016602482015275139bdd08185b1b1bddd959081d1bc819195c1bdcda5d60521b604482015260640161087e565b613c28848281518110613bed57613bed615738565b602002602001015160096000856001600160a01b03166001600160a01b03168152602001908152602001600020614ab890919063ffffffff16565b613c3157600080fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166323b872dd8330878581518110613c7457613c74615738565b60200260200101516040518463ffffffff1660e01b8152600401613c9a93929190615a12565b600060405180830381600087803b158015613cb457600080fd5b505af1158015613cc8573d6000803e3d6000fd5b50505050838181518110613cde57613cde615738565b60200260200101517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c83604051613d2491906001600160a01b0391909116815260200190565b60405180910390a28160066000868481518110613d4357613d43615738565b6020908102919091018101518252810191909152604001600090812080546001600160a01b0319166001600160a01b03938416179055600354865191921690635c6d96a9907f000000000000000000000000000000000000000000000000000000000000000090889086908110613dbc57613dbc615738565b60200260200101516040518363ffffffff1660e01b8152600401613df59291906001600160a01b03929092168252602082015260400190565b60206040518083038186803b158015613e0d57600080fd5b505afa158015613e21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e45919061598f565b9050806001600160801b031660066000878581518110613e6757613e67615738565b60200260200101518152602001908152602001600020600101819055508315613eca57613eca858381518110613e9f57613e9f615738565b602002602001015187836001600160801b0316600560008b8152602001908152602001600020613303565b50600101613b55565b5050505050565b6001600160a01b038316613f91576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613f35576040519150601f19603f3d011682016040523d82523d6000602084013e613f3a565b606091505b5050905080613f8b5760405162461bcd60e51b815260206004820152601c60248201527f7472616e736665722072657761726420746f6b656e206661696c656400000000604482015260640161087e565b50505050565b613fa56001600160a01b0384168383614c10565b505050565b600083815260056020908152604080832087845260068352818420546007845282852088865290935292206001600160a01b03909116903382148061401c57508254600160c01b900463ffffffff164263ffffffff1611801561401c57503360009081526002602052604090205460ff165b6140725760405162461bcd60e51b815260206004820152602160248201527f657869743a206e6f74206f776e6572206f7220706f6f6c206e6f7420656e64656044820152601960fa1b606482015260840161087e565b600581015485158015906140865750808611155b6140c65760405162461bcd60e51b8152602060048201526011602482015270657869743a20696e76616c6964206c697160781b604482015260640161087e565b60006140d287836159ac565b905060006140e08a8a612d81565b90508060a001518660010160008282546140fa91906159c3565b9091555050805184546001600160801b0319166001600160801b039091161784556005840182905560005b600287015481101561439957600061414c85896002018481548110612c5657612c56615738565b905080156141c6578086600301838154811061416a5761416a615738565b90600052602060002001600082825461418391906159c3565b92505081905550808860020183815481106141a0576141a0615738565b906000526020600020906002020160010160008282546141c091906159ac565b90915550505b60006142058760030184815481106141e0576141e0615738565b90600052602060002001548560400151896001018681548110612cc357612cc3615738565b9050600087600201848154811061421e5761421e615738565b9060005260206000200154905081600014614275578188600101858154811061424957614249615738565b90600052602060002001600082825461426291906159c3565b90915550614272905082826159c3565b90505b8015614385578a1561436257600088600201858154811061429857614298615738565b90600052602060002001819055506142df8a60020185815481106142be576142be615738565b60009182526020909120600290910201546001600160a01b03168a83613eda565b808e7f1ec92956b13869de207e232e60c65e35826c5e12b7fdc6d70b083b5a4fd267038b8d600201888154811061431857614318615738565b600091825260209091206002909102015460405161435592916001600160a01b0316906001600160a01b0392831681529116602082015260400190565b60405180910390a3614385565b8088600201858154811061437857614378615738565b6000918252602090912001555b5050508061439290615764565b9050614125565b508161447b5760008a81526007602090815260408083208c8452909152812080546001600160801b0319168155906143d46001830182615077565b6143e2600283016000615077565b6143f0600383016000615077565b5060006004828101829055600590920181905590870180549161441283615ad7565b909155505060008a815260086020526040902061442f908a6144c0565b61447b5760405162461bcd60e51b815260206004820152601a60248201527f4661696c20746f2072656d6f7665206a6f696e6564506f6f6c73000000000000604482015260640161087e565b60405133815288908a908c907f275029c7b988945c03ac5499c0d532fce79ce36efab42e1b3f180a62001cad2c9060200160405180910390a450505050505050505050565b6000613a4c8383614c62565b60606000613a4c83614d55565b801561457b57604051630c479e6560e21b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063311e799490602401602060405180830381600087803b15801561454157600080fd5b505af1158015614555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145799190615a82565b505b60408051608081018252848152600060208201818152828401918252606083018681529351637686c6e960e11b815283516004820152905160248201529051604482015291516064830152907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ed0d8dd2906084015b606060405180830381600087803b15801561461657600080fd5b505af115801561462a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fe9190615aee565b7f0000000000000000000000000000000000000000000000000000000000000000811561484a57866001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614156147795760405163bac37ef760e01b8152600481018690526001600160a01b03848116602483015282169063bac37ef790604401600060405180830381600087803b1580156146f957600080fd5b505af115801561470d573d6000803e3d6000fd5b505060405163bf1316c160e01b81526001600160a01b038416925063bf1316c1915061474190899088908890600401615b1c565b600060405180830381600087803b15801561475b57600080fd5b505af115801561476f573d6000803e3d6000fd5b5050505050614910565b856001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316141561484a5760405163bf1316c160e01b81526001600160a01b0382169063bf1316c1906147e3908a9089908890600401615b1c565b600060405180830381600087803b1580156147fd57600080fd5b505af1158015614811573d6000803e3d6000fd5b505060405163bac37ef760e01b8152600481018790526001600160a01b0386811660248301528416925063bac37ef79150604401614741565b60405163bf1316c160e01b81526001600160a01b0382169063bf1316c19061487a908a9089908890600401615b1c565b600060405180830381600087803b15801561489457600080fd5b505af11580156148a8573d6000803e3d6000fd5b505060405163bf1316c160e01b81526001600160a01b038416925063bf1316c191506148dc90899088908890600401615b1c565b600060405180830381600087803b1580156148f657600080fd5b505af115801561490a573d6000803e3d6000fd5b50505050505b505050505050565b6040805160a0810182528481526001600160801b03848116602083019081526000838501818152606085019182526080850187815295516398e04d7760e01b81528551600482015292519093166024830152915160448201529051606482015291516084830152907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906398e04d779060a4016145fc565b600082826149c78688615a9b565b6149d19190615a9b565b6149db9190615b55565b95945050505050565b60008064e8d4a510006149f78587615a9b565b614a019190615b55565b9050828111614a115760006149db565b6149db83826159ac565b600081614a2e575064e8d4a51000613a4c565b6000614a3a8486615b69565b90506149db83614a4f64e8d4a5100084615a9b565b614a599190615b55565b64e8d4a51000614db1565b60008084614a784263ffffffff1686614dc7565b614a8291906159ac565b90506000614a9482600160601b615a9b565b9050838111614aa4576000614aae565b614aae84826159ac565b9695505050505050565b6000613a4c8383614dde565b600084614ad357506000614aae565b600087614ae08789615b69565b12614af457614aef8688615b69565b614af6565b875b60035460405163528ee47960e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018790529293506000929091169063a51dc8f29060440160206040518083038186803b158015614b6857600080fd5b505afa158015614b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ba09190615a82565b614baa9086615ba8565b614bb48388615ba8565b614bbe9190615c2d565b90506000614bcc86886159c3565b9050614bd88183615c6e565b9a9950505050505050505050565b6000826000018281548110614bfd57614bfd615738565b9060005260206000200154905092915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613fa5908490614e2d565b60008181526001830160205260408120548015614d4b576000614c866001836159ac565b8554909150600090614c9a906001906159ac565b9050818114614cff576000866000018281548110614cba57614cba615738565b9060005260206000200154905080876000018481548110614cdd57614cdd615738565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614d1057614d10615c9c565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ef9565b6000915050611ef9565b606081600001805480602002602001604051908101604052809291908181526020018280548015614da557602002820191906000526020600020905b815481526020019060010190808311614d91575b50505050509050919050565b600081831015614dc15782613a4c565b50919050565b600081831015614dd75781613a4c565b5090919050565b6000818152600183016020526040812054614e2557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ef9565b506000611ef9565b6000614e82826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614eff9092919063ffffffff16565b805190915015613fa55780806020019051810190614ea09190615aba565b613fa55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161087e565b6060614f0e8484600085614f16565b949350505050565b606082471015614f775760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161087e565b843b614fc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161087e565b600080866001600160a01b03168587604051614fe19190615cde565b60006040518083038185875af1925050503d806000811461501e576040519150601f19603f3d011682016040523d82523d6000602084013e615023565b606091505b509150915061503382828661503e565b979650505050505050565b6060831561504d575081613a4c565b82511561505d5782518084602001fd5b8160405162461bcd60e51b815260040161087e9190615cfa565b508054600082559060005260206000209081019061509591906150e3565b50565b8280548282559060005260206000209081019282156150d3579160200282015b828111156150d35782518255916020019190600101906150b8565b506150df9291506150e3565b5090565b5b808211156150df57600081556001016150e4565b803563ffffffff8116811461510c57600080fd5b919050565b60008083601f84011261512357600080fd5b5081356001600160401b0381111561513a57600080fd5b6020830191508360208260051b850101111561515557600080fd5b9250929050565b60008060008060008060a0878903121561517557600080fd5b86359550615185602088016150f8565b9450615193604088016150f8565b935060608701356001600160401b038111156151ae57600080fd5b6151ba89828a01615111565b979a9699509497949695608090950135949350505050565b6001600160a01b038116811461509557600080fd5b6000602082840312156151f957600080fd5b8135613a4c816151d2565b6000806000806040858703121561521a57600080fd5b84356001600160401b038082111561523157600080fd5b61523d88838901615111565b9096509450602087013591508082111561525657600080fd5b5061526387828801615111565b95989497509550505050565b60006020828403121561528157600080fd5b5035919050565b600081518084526020808501945080840160005b838110156152b85781518752958201959082019060010161529c565b509495945050505050565b6001600160a01b03898116825263ffffffff8981166020808501919091529089166040840152606083018890526080830187905260a0830186905261010060c08401819052855190840181905260009261012085019287810192855b8181101561533d57845184168652948201949382019360010161531f565b505050505082810360e08401526153548185615288565b9b9a5050505050505050505050565b60008060008060006060868803121561537b57600080fd5b8535945060208601356001600160401b038082111561539957600080fd5b6153a589838a01615111565b909650945060408801359150808211156153be57600080fd5b506153cb88828901615111565b969995985093965092949392505050565b6000806000606084860312156153f157600080fd5b505081359360208301359350604090920135919050565b602081526000613a4c6020830184615288565b801515811461509557600080fd5b60006020828403121561543b57600080fd5b8135613a4c8161541b565b6000806020838503121561545957600080fd5b82356001600160401b0381111561546f57600080fd5b61547b85828601615111565b90969095509350505050565b60008060006040848603121561549c57600080fd5b8335925060208401356001600160401b038111156154b957600080fd5b6154c586828701615111565b9497909650939450505050565b600080604083850312156154e557600080fd5b82356154f0816151d2565b915060208301356155008161541b565b809150509250929050565b60008060008060008060008060c0898b03121561552757600080fd5b8835615532816151d2565b975061554060208a016150f8565b965061554e60408a016150f8565b955060608901356001600160401b038082111561556a57600080fd5b6155768c838d01615111565b909750955060808b013591508082111561558f57600080fd5b5061559c8b828c01615111565b999c989b50969995989497949560a00135949350505050565b600080604083850312156155c857600080fd5b50508035926020909101359150565b600080600080600080600060c0888a0312156155f257600080fd5b87356001600160401b0381111561560857600080fd5b6156148a828b01615111565b90985096505060208801359450604088013593506060880135615636816151d2565b925060808801356156468161541b565b8092505060a0880135905092959891949750929550565b6001600160801b038116811461509557600080fd5b600080600080600080600061010080898b03121561568f57600080fd5b8835975060208901356156a18161565d565b965060408901359550606089013594506080890135935060a08901356156c68161541b565b92508881018a10156156d757600080fd5b5060c08801905092959891949750929550565b8381526060602082015260006157036060830185615288565b8281036040840152614aae8185615288565b6020808252600990820152683337b93134b23232b760b91b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156157785761577861574e565b5060010190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600e908201526d0d2dcecc2d8d2c840d8cadccee8d60931b604082015260600190565b6000808335601e198436030181126157f557600080fd5b8301803591506001600160401b0382111561580f57600080fd5b60200191503681900382131561515557600080fd5b634e487b7160e01b600052604160045260246000fd5b604051602081016001600160401b038111828210171561585c5761585c615824565b60405290565b604051601f8201601f191681016001600160401b038111828210171561588a5761588a615824565b604052919050565b600060208083850312156158a557600080fd5b82356001600160401b03808211156158bc57600080fd5b81850191508282870312156158d057600080fd5b6158d861583a565b8235828111156158e757600080fd5b80840193505086601f8401126158fc57600080fd5b82358281111561590e5761590e615824565b8060051b925061591f858401615862565b818152928401850192858101908985111561593957600080fd5b948601945b848610156159575785358252948601949086019061593e565b83525090979650505050505050565b6020808252600f908201526e506f6f6c206e6f742065786973747360881b604082015260600190565b6000602082840312156159a157600080fd5b8151613a4c8161565d565b6000828210156159be576159be61574e565b500390565b600082198211156159d6576159d661574e565b500190565b60208082526018908201527f7370656369616c20666561747572652064697361626c65640000000000000000604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215615a4857600080fd5b8151613a4c816151d2565b60008060408385031215615a6657600080fd5b8251615a71816151d2565b6020840151909250615500816151d2565b600060208284031215615a9457600080fd5b5051919050565b6000816000190483118215151615615ab557615ab561574e565b500290565b600060208284031215615acc57600080fd5b8151613a4c8161541b565b600081615ae657615ae661574e565b506000190190565b600080600060608486031215615b0357600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b0393841681526020810192909252909116604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082615b6457615b64615b3f565b500490565b60008083128015600160ff1b850184121615615b8757615b8761574e565b6001600160ff1b0384018313811615615ba257615ba261574e565b50500390565b60006001600160ff1b0381841382841380821686840486111615615bce57615bce61574e565b600160ff1b6000871282811687830589121615615bed57615bed61574e565b60008712925087820587128484161615615c0957615c0961574e565b87850587128184161615615c1f57615c1f61574e565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615615c4f57615c4f61574e565b600160ff1b8390038412811615615c6857615c6861574e565b50500190565b600082615c7d57615c7d615b3f565b600160ff1b821460001984141615615c9757615c9761574e565b500590565b634e487b7160e01b600052603160045260246000fd5b60005b83811015615ccd578181015183820152602001615cb5565b83811115613f8b5750506000910152565b60008251615cf0818460208701615cb2565b9190910192915050565b6020815260008251806020840152615d19816040850160208701615cb2565b601f01601f1916919091016040019291505056fea164736f6c6343000809000a000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48000000000000000000000000035be3f4fd8239a35a7f120756d4d69e5c5e10870
Deployed Bytecode
0x6080604052600436106101fd5760003560e01c806375829def1161010d578063b36b26c5116100a0578063c7ca58701161006f578063c7ca58701461074b578063d1941b061461076b578063dc168a921461078b578063e7762a0c146107ba578063f851a4401461082f57600080fd5b8063b36b26c5146106bc578063b63ff916146106dc578063b82562751461070c578063bb5ae7751461072c57600080fd5b806399fbab88116100dc57806399fbab881461052f578063ac4afa381461058e578063affe737914610631578063b221e5fd1461064657600080fd5b806375829def146104af5780638bcc4166146104cf57806391fb2f15146104ef578063983d95ce1461050f57600080fd5b806347ccca021161019057806361657b121161015f57806361657b121461040f57806366b5a6641461042f578063683f3eda1461044f5780636d44a3b21461046f578063705b5bef1461048f57600080fd5b806347ccca021461036e57806349b35168146103a257806350523cea146103cf578063598b8e71146103ef57600080fd5b80632f380b35116101cc5780632f380b35146102b45780633fc8cef3146102e857806341e817ab14610334578063430ccd9b1461035457600080fd5b8063078ded5d14610209578063081e3eda1461022b57806313e7c9d814610254578063180f80361461029457600080fd5b3661020457005b600080fd5b34801561021557600080fd5b5061022961022436600461515c565b61084f565b005b34801561023757600080fd5b5061024160045481565b6040519081526020015b60405180910390f35b34801561026057600080fd5b5061028461026f3660046151e7565b60026020526000908152604090205460ff1681565b604051901515815260200161024b565b3480156102a057600080fd5b506102296102af366004615204565b610b0b565b3480156102c057600080fd5b506102d46102cf36600461526f565b610c8d565b60405161024b9897969594939291906152c3565b3480156102f457600080fd5b5061031c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b03909116815260200161024b565b34801561034057600080fd5b5061022961034f366004615363565b610e37565b34801561036057600080fd5b50600b546102849060ff1681565b34801561037a57600080fd5b5061031c7f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48081565b3480156103ae57600080fd5b506103c26103bd3660046153dc565b61118b565b60405161024b9190615408565b3480156103db57600080fd5b506102296103ea366004615429565b6112e3565b3480156103fb57600080fd5b5061022961040a366004615446565b611361565b34801561041b57600080fd5b5061022961042a366004615204565b6113d3565b34801561043b57600080fd5b5061022961044a366004615363565b611507565b34801561045b57600080fd5b5061022961046a366004615487565b6115d8565b34801561047b57600080fd5b5061022961048a3660046154d2565b611674565b34801561049b57600080fd5b506103c26104aa36600461526f565b6116fd565b3480156104bb57600080fd5b506102296104ca3660046151e7565b6117b5565b3480156104db57600080fd5b506102296104ea3660046151e7565b61184f565b3480156104fb57600080fd5b5061022961050a36600461550b565b6118c7565b34801561051b57600080fd5b5061022961052a366004615446565b611b60565b34801561053b57600080fd5b5061056f61054a36600461526f565b600660205260009081526040902080546001909101546001600160a01b039091169082565b604080516001600160a01b03909316835260208301919091520161024b565b34801561059a57600080fd5b506105f06105a936600461526f565b60056020526000908152604090208054600182015460038301546004909301546001600160a01b0383169363ffffffff600160a01b8504811694600160c01b900416929186565b604080516001600160a01b0397909716875263ffffffff958616602088015293909416928501929092526060840152608083015260a082015260c00161024b565b34801561063d57600080fd5b50610229611e30565b34801561065257600080fd5b506106976106613660046155b5565b60076020908152600092835260408084209091529082529020805460048201546005909201546001600160801b03909116919083565b604080516001600160801b03909416845260208401929092529082015260600161024b565b3480156106c857600080fd5b506103c26106d73660046151e7565b611ed5565b3480156106e857600080fd5b506102846106f736600461526f565b600a6020526000908152604090205460ff1681565b34801561071857600080fd5b506102296107273660046155d7565b611eff565b34801561073857600080fd5b50600b5461028490610100900460ff1681565b34801561075757600080fd5b50610229610766366004615672565b6122ad565b34801561077757600080fd5b50610229610786366004615446565b6126d6565b34801561079757600080fd5b506107ab6107a63660046155b5565b612b10565b60405161024b939291906156ea565b3480156107c657600080fd5b506107da6107d53660046155b5565b612d81565b60405161024b9190600060c0820190506001600160801b0383511682526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015292915050565b34801561083b57600080fd5b5060015461031c906001600160a01b031681565b3360009081526002602052604090205460ff166108875760405162461bcd60e51b815260040161087e90615715565b60405180910390fd5b6000868152600560205260409020805463ffffffff428116600160a01b9092041611806108c45750805463ffffffff428116600160c01b90920416105b6109105760405162461bcd60e51b815260206004820152601960248201527f72656e65773a20696e76616c696420706f6f6c20737461746500000000000000604482015260640161087e565b6002810154831461095b5760405162461bcd60e51b81526020600482015260156024820152740e4cadccaee7440d2dcecc2d8d2c840d8cadccee8d605b1b604482015260640161087e565b4263ffffffff168663ffffffff1611801561098157508563ffffffff168563ffffffff16115b6109c45760405162461bcd60e51b815260206004820152601460248201527372656e65773a20696e76616c69642074696d657360601b604482015260640161087e565b600481015415610a0f5760405162461bcd60e51b815260206004820152601660248201527572656e65773a20706f6f6c20686173207374616b657360501b604482015260640161087e565b805463ffffffff868116600160c01b0263ffffffff60c01b19918916600160a01b029190911667ffffffffffffffff60a01b1990921691909117178155600060018201819055600382018390555b83811015610ab757848482818110610a7757610a77615738565b90506020020135826002018281548110610a9357610a93615738565b6000918252602090912060016002909202010155610ab081615764565b9050610a5d565b506040805163ffffffff80891682528716602082015290810183905287907feda7bcc7e20158ff9fa87a4200758e927bbb3c8823e648403bdd6053b96dd0ad9060600160405180910390a250505050505050565b60026000541415610b2e5760405162461bcd60e51b815260040161087e9061577f565b60026000558281808214610b545760405162461bcd60e51b815260040161087e906157b6565b60005b85811015610c7f573360066000898985818110610b7657610b76615738565b60209081029290920135835250810191909152604001600020546001600160a01b031614610bdb5760405162461bcd60e51b81526020600482015260126024820152713430b93b32b9ba1d103737ba1037bbb732b960711b604482015260640161087e565b6000858583818110610bef57610bef615738565b9050602002810190610c0191906157de565b810190610c0e9190615892565b905060005b815151811015610c6c57610c5c898985818110610c3257610c32615738565b9050602002013583600001518381518110610c4f57610c4f615738565b6020026020010151612fc9565b610c6581615764565b9050610c13565b505080610c7890615764565b9050610b57565b505060016000555050505050565b6000818152600560205260409020805460018201546003830154600484015460028501546001600160a01b0385169563ffffffff600160a01b8704811696600160c01b900416949392916060918291806001600160401b03811115610cf457610cf4615824565b604051908082528060200260200182016040528015610d1d578160200160208202803683370190505b509350806001600160401b03811115610d3857610d38615824565b604051908082528060200260200182016040528015610d61578160200160208202803683370190505b50925060005b81811015610e2957826002018181548110610d8457610d84615738565b600091825260209091206002909102015485516001600160a01b0390911690869083908110610db557610db5615738565b60200260200101906001600160a01b031690816001600160a01b031681525050826002018181548110610dea57610dea615738565b906000526020600020906002020160010154848281518110610e0e57610e0e615738565b6020908102919091010152610e2281615764565b9050610d67565b505050919395975091939597565b60026000541415610e5a5760405162461bcd60e51b815260040161087e9061577f565b60026000558281808214610e805760405162461bcd60e51b815260040161087e906157b6565b8660045411610ea15760405162461bcd60e51b815260040161087e90615966565b6000878152600560205260409020805463ffffffff428116600160a01b9092041611801590610ee357508054600160c01b900463ffffffff164263ffffffff16105b610f1e5760405162461bcd60e51b815260206004820152600c60248201526b496e76616c69642074696d6560a01b604482015260640161087e565b60005b8681101561117b5733600660008a8a85818110610f4057610f40615738565b60209081029290920135835250810191909152604001600020546001600160a01b031614610f9c5760405162461bcd60e51b81526020600482015260096024820152682737ba1037bbb732b960b91b604482015260640161087e565b6003546001600160a01b0316635c6d96a97f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4808a8a85818110610fe057610fe0615738565b6040516001600160e01b031960e087901b1681526001600160a01b039094166004850152602002919091013560248301525060440160206040518083038186803b15801561102d57600080fd5b505afa158015611041573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611065919061598f565b6001600160801b0316600660008a8a8581811061108457611084615738565b905060200201358152602001908152602001600020600101819055506000600760008a8a858181106110b8576110b8615738565b90506020020135815260200190815260200160002060008b8152602001908152602001600020905080600501546000141561112e5761112989898481811061110257611102615738565b905060200201358b89898681811061111c5761111c615738565b9050602002013586613303565b61116a565b61116a89898481811061114357611143615738565b905060200201358b89898681811061115d5761115d615738565b90506020020135866137a9565b5061117481615764565b9050610f21565b5050600160005550505050505050565b6060818311156111d35760405162461bcd60e51b81526020600482015260136024820152720cce4deda92dcc8caf0407c40e8de92dcc8caf606b1b604482015260640161087e565b60008481526008602052604090206111ea90613a36565b821061122c5760405162461bcd60e51b81526020600482015260116024820152700e8de92dcc8caf0407c7a40d8cadccee8d607b1b604482015260640161087e565b61123683836159ac565b6112419060016159c3565b6001600160401b0381111561125857611258615824565b604051908082528060200260200182016040528015611281578160200160208202803683370190505b509050825b8281116112db5760008581526008602052604090206112a59082613a40565b826112b086846159ac565b815181106112c0576112c0615738565b60209081029190910101526112d481615764565b9050611286565b509392505050565b6001546001600160a01b0316331461130d5760405162461bcd60e51b815260040161087e90615715565b600b80548215156101000261ff00199091161790556040517f294aa6bf970997b8c55a069e787eae16138f63ad315362696337d14ef42281ea9061135690831515815260200190565b60405180910390a150565b600260005414156113845760405162461bcd60e51b815260040161087e9061577f565b60026000819055506113ca600083838080602002602001604051908101604052809392919081815260200183836020028082843760009201829052509250613a53915050565b50506001600055565b6001546001600160a01b031633146113fd5760405162461bcd60e51b815260040161087e90615715565b828180821461141e5760405162461bcd60e51b815260040161087e906157b6565b60005b858110156114fe5761147287878381811061143e5761143e615738565b905060200201602081019061145391906151e7565b3387878581811061146657611466615738565b90506020020135613eda565b84848281811061148457611484615738565b905060200201357f4042b7789d1f6c4d5a798b447cfb918e82b64dd68b81d78ddc4dd1944ba5c51c8888848181106114be576114be615738565b90506020020160208101906114d391906151e7565b6040516001600160a01b03909116815260200160405180910390a26114f781615764565b9050611421565b50505050505050565b6002600054141561152a5760405162461bcd60e51b815260040161087e9061577f565b600260005582818082146115505760405162461bcd60e51b815260040161087e906157b6565b86600454116115715760405162461bcd60e51b815260040161087e90615966565b60005b858110156115c9576115b987878381811061159157611591615738565b90506020020135898787858181106115ab576115ab615738565b905060200201356001613faa565b6115c281615764565b9050611574565b50506001600055505050505050565b600b54610100900460ff166115ff5760405162461bcd60e51b815260040161087e906159db565b600260005414156116225760405162461bcd60e51b815260040161087e9061577f565b600260008190555061166a8383838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525060019250613a53915050565b5050600160005550565b6001546001600160a01b0316331461169e5760405162461bcd60e51b815260040161087e90615715565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915591519182527f2ee52be9d342458b3d25e07faada7ff9bc06723b4aa24edb6321ac1316b8a9dd910160405180910390a25050565b60008181526008602052604081206060919061171890613a36565b9050806001600160401b0381111561173257611732615824565b60405190808252806020026020018201604052801561175b578160200160208202803683370190505b50915060005b818110156117ae5760008481526008602052604090206117819082613a40565b83828151811061179357611793615738565b60209081029190910101526117a781615764565b9050611761565b5050919050565b6001546001600160a01b031633146117df5760405162461bcd60e51b815260040161087e90615715565b6001600160a01b0381166118055760405162461bcd60e51b815260040161087e90615715565b600180546001600160a01b0319166001600160a01b0383169081179091556040517fda7b0a7bc965abdec8a1a995575a891838264c2968e14bd456c5391827b7aa3090600090a250565b6001546001600160a01b031633146118795760405162461bcd60e51b815260040161087e90615715565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f7b9adf13852d5b3e153f2a442b9aa3a4570da8f9b9046c60410b17e8034fe33c90602001611356565b3360009081526002602052604090205460ff166118f65760405162461bcd60e51b815260040161087e90615715565b83828082146119175760405162461bcd60e51b815260040161087e906157b6565b4263ffffffff168963ffffffff161015801561193e57508863ffffffff168863ffffffff16115b6119835760405162461bcd60e51b8152602060048201526016602482015275616464506f6f6c3a20696e76616c69642074696d657360501b604482015260640161087e565b6000600454905060006005600083815260200190815260200160002090508b8160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055508a8160000160146101000a81548163ffffffff021916908363ffffffff160217905550898160000160186101000a81548163ffffffff021916908363ffffffff1602179055506000816001018190555084816003018190555060005b88811015611ae3578160020160405180604001604052808c8c85818110611a4f57611a4f615738565b9050602002016020810190611a6491906151e7565b6001600160a01b031681526020018a8a85818110611a8457611a84615738565b60209081029290920135909252835460018082018655600095865294829020845160029092020180546001600160a01b0319166001600160a01b0390921691909117815592015191909201555080611adb81615764565b915050611a26565b5060048054906000611af483615764565b9091555050604080516001600160a01b038e16815263ffffffff8d811660208301528c168183015260608101879052905183917f251199ba7b3e7a12b779b3f606eaf369cecc0eac8bcbacaadcf08079e8c5940f919081900360800190a2505050505050505050505050565b60026000541415611b835760405162461bcd60e51b815260040161087e9061577f565b6002600090815533905b82811015611e2557816001600160a01b031660066000868685818110611bb557611bb5615738565b60209081029290920135835250810191909152604001600020546001600160a01b031614611c1b5760405162461bcd60e51b81526020600482015260136024820152723bb4ba34323930bb9d103737ba1037bbb732b960691b604482015260640161087e565b611c4e60086000868685818110611c3457611c34615738565b905060200201358152602001908152602001600020613a36565b15611c9b5760405162461bcd60e51b815260206004820152601860248201527f77697468647261773a206e6f7420657869746564207965740000000000000000604482015260640161087e565b60066000858584818110611cb157611cb1615738565b60209081029290920135835250810191909152604001600090812080546001600160a01b031916815560010155611d1a848483818110611cf357611cf3615738565b6001600160a01b0386166000908152600960209081526040909120939102013590506144c0565b611d2357600080fd5b7f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4806001600160a01b03166323b872dd3084878786818110611d6657611d66615738565b905060200201356040518463ffffffff1660e01b8152600401611d8b93929190615a12565b600060405180830381600087803b158015611da557600080fd5b505af1158015611db9573d6000803e3d6000fd5b50505050838382818110611dcf57611dcf615738565b6040516001600160a01b038616815260209182029390930135927f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a942436492500160405180910390a2611e1e81615764565b9050611b8d565b505060016000555050565b6001546001600160a01b03163314611e5a5760405162461bcd60e51b815260040161087e90615715565b600b5460ff1615611e9d5760405162461bcd60e51b815260206004820152600d60248201526c496e76616c69642076616c756560981b604482015260640161087e565b600b805460ff191660011790556040517f1d8c7af3ae0426053ea40080543aa1cbe5bea5cdb7a55888b4cca96eea0493e490600090a1565b6001600160a01b0381166000908152600960205260409020606090611ef9906144cc565b92915050565b60026000541415611f225760405162461bcd60e51b815260040161087e9061577f565b6002600055600b54610100900460ff16611f4e5760405162461bcd60e51b815260040161087e906159db565b804263ffffffff161115611f985760405162461bcd60e51b815260206004820152601160248201527018db185a5b5199594e88195e1c1a5c9959607a1b604482015260640161087e565b6000878790509050600080856001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015611fdc57600080fd5b505afa158015611ff0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120149190615a36565b866001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561204d57600080fd5b505afa158015612061573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120859190615a36565b9150915060005b8381101561228d5733600660008d8d858181106120ab576120ab615738565b60209081029290920135835250810191909152604001600020546001600160a01b0316146121115760405162461bcd60e51b815260206004820152601360248201527231b630b4b6a332b29d103737ba1037bbb732b960691b604482015260640161087e565b60035460009081906001600160a01b0316626349fb7f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4808f8f8781811061215957612159615738565b6040516001600160e01b031960e087901b1681526001600160a01b0390941660048501526020029190910135602483015250604401604080518083038186803b1580156121a557600080fd5b505afa1580156121b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121dd9190615a53565b91509150846001600160a01b0316826001600160a01b03161480156122135750836001600160a01b0316816001600160a01b0316145b61225f5760405162461bcd60e51b815260206004820152601e60248201527f636c61696d4665653a20746f6b656e2070616972206e6f74206d617463680000604482015260640161087e565b6122838d8d8581811061227457612274615738565b905060200201358860016144d9565b505060010161208c565b5061229c82828a8a338a61464e565b505060016000555050505050505050565b600260005414156122d05760405162461bcd60e51b815260040161087e9061577f565b6002600055600b54610100900460ff166122fc5760405162461bcd60e51b815260040161087e906159db565b824263ffffffff1611156123525760405162461bcd60e51b815260206004820152601860248201527f72656d6f76654c69717569646974793a20657870697265640000000000000000604482015260640161087e565b6000878152600660205260409020546001600160a01b031633146123b85760405162461bcd60e51b815260206004820152601a60248201527f72656d6f76654c69717569646974793a206e6f74206f776e6572000000000000604482015260640161087e565b600354604051635c6d96a960e01b81526001600160a01b037f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48081166004830152602482018a90526000921690635c6d96a99060440160206040518083038186803b15801561242557600080fd5b505afa158015612439573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245d919061598f565b6001600160801b031690506000876001600160801b031611801561248a575080876001600160801b031611155b6124e15760405162461bcd60e51b815260206004820152602260248201527f72656d6f76654c69717569646974793a20696e76616c6964206c697175696469604482015261747960f01b606482015260840161087e565b6124f46001600160801b038816826159ac565b6000898152600660209081526040808320600101849055600890915281209192509061251f906144cc565b905060005b81518110156125e35760008a81526007602052604081208351829085908590811061255157612551615738565b60200260200101518152602001908152602001600020600501549050600084821161257d576000612587565b61258785836159ac565b905080156125d9576125d98c8585815181106125a5576125a5615738565b602002602001015183896001600281106125c1576125c1615738565b6020020160208101906125d49190615429565b613faa565b5050600101612524565b50600354604051626349fb60e01b81526001600160a01b037f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48081166004830152602482018c90526000928392911690626349fb90604401604080518083038186803b15801561265157600080fd5b505afa158015612665573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126899190615a53565b915091506126988b8b89614918565b6126a56020860186615429565b156126b6576126b68b8860006144d9565b6126c482828b8b338b61464e565b50506001600055505050505050505050565b600260005414156126f95760405162461bcd60e51b815260040161087e9061577f565b60026000908155600b54339160ff909116905b83811015612b0457826001600160a01b03166006600087878581811061273457612734615738565b60209081029290920135835250810191909152604001600020546001600160a01b03161461279a5760405162461bcd60e51b81526020600482015260136024820152723bb4ba34323930bb9d103737ba1037bbb732b960691b604482015260640161087e565b6001600a60008787858181106127b2576127b2615738565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055506000612813600860008888868181106127f9576127f9615738565b9050602002013581526020019081526020016000206144cc565b905060005b81518110156128f057600082828151811061283557612835615738565b60209081029190910181015160008181526005909252604082206004018054600019019055915060079089898781811061287157612871615738565b602090810292909201358352508181019290925260409081016000908120848252909252812080546001600160801b0319168155906128b36001830182615077565b6128c1600283016000615077565b6128cf600383016000615077565b50600060048201819055600590910155506128e981615764565b9050612818565b506006600087878581811061290757612907615738565b60209081029290920135835250810191909152604001600090812080546001600160a01b03191681556001015582612a015761297586868481811061294e5761294e615738565b6001600160a01b0388166000908152600960209081526040909120939102013590506144c0565b61297e57600080fd5b60005b81518110156129ff57600082828151811061299e5761299e615738565b602002602001015190506129e581600860008b8b898181106129c2576129c2615738565b9050602002013581526020019081526020016000206144c090919063ffffffff16565b6129ee57600080fd5b506129f881615764565b9050612981565b505b7f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4806001600160a01b03166323b872dd3086898987818110612a4457612a44615738565b905060200201356040518463ffffffff1660e01b8152600401612a6993929190615a12565b600060405180830381600087803b158015612a8357600080fd5b505af1158015612a97573d6000803e3d6000fd5b50505050858583818110612aad57612aad615738565b6040516001600160a01b038816815260209182029390930135927f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd969592500160405180910390a250612afd81615764565b905061270c565b50506001600055505050565b600081815260056020818152604080842086855260078352818520868652909252832091820154606092839291612b895760405162461bcd60e51b815260206004820152601b60248201527f67657455736572496e666f3a206e6f74206a6f696e6564207965740000000000604482015260640161087e565b60028201546001600160401b03811115612ba557612ba5615824565b604051908082528060200260200182016040528015612bce578160200160208202803683370190505b5060028301549094506001600160401b03811115612bee57612bee615824565b604051908082528060200260200182016040528015612c17578160200160208202803683370190505b5092506000612c268888612d81565b905060005b6002840154811015612d6f576000612c778460050154866002018481548110612c5657612c56615738565b906000526020600020906002020160010154856060015186608001516149b9565b90506000612cd382866003018581548110612c9457612c94615738565b9060005260206000200154612ca991906159c3565b8560400151876001018681548110612cc357612cc3615738565b90600052602060002001546149e4565b905080856002018481548110612ceb57612ceb615738565b9060005260206000200154612d0091906159c3565b888481518110612d1257612d12615738565b602002602001018181525050846001018381548110612d3357612d33615738565b9060005260206000200154878481518110612d5057612d50615738565b602002602001018181525050505080612d6890615764565b9050612c2b565b50816005015495505050509250925092565b612dc36040518060c0016040528060006001600160801b0316815260200160008152602001600081526020016000815260200160008152602001600081525090565b6000828152600560209081526040808320868452600783528184208685529092529182902060035482549351632106297960e11b8152929391926001600160a01b039182169263420c52f292612e42929116907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a480908a90600401615a12565b60206040518083038186803b158015612e5a57600080fd5b505afa158015612e6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e92919061598f565b6001600160801b0316835260035482546040516339bb866b60e11b81526001600160a01b03928316926373770cd692612ef4929116907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a480908a90600401615a12565b60206040518083038186803b158015612f0c57600080fd5b505afa158015612f20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f449190615a82565b6020840181905260048201546003840154612f60929190614a1b565b604084015281546001830154612f8e9163ffffffff600160a01b8204811692600160c01b9092041690614a64565b6060840152805483516001600160801b03918216900316608084018190526005820154612fbb9190615a9b565b60a084015250909392505050565b8060045411612fea5760405162461bcd60e51b815260040161087e90615966565b60008181526005602081815260408084208685526006835281852054600784528286208787529093529320918201546001600160a01b0390911691906130725760405162461bcd60e51b815260206004820152601760248201527f686172766573743a206e6f74206a6f696e656420796574000000000000000000604482015260640161087e565b600061307e8686612d81565b90508060a0015184600101600082825461309891906159c3565b9091555050805182546001600160801b0319166001600160801b0390911617825560005b60028501548110156114fe5760006130e78460050154876002018481548110612c5657612c56615738565b90508015613161578084600301838154811061310557613105615738565b90600052602060002001600082825461311e91906159c3565b925050819055508086600201838154811061313b5761313b615738565b9060005260206000209060020201600101600082825461315b91906159ac565b90915550505b60006131a085600301848154811061317b5761317b615738565b90600052602060002001548560400151876001018681548110612cc357612cc3615738565b90506000818660020185815481106131ba576131ba615738565b90600052602060002001546131cf91906159c3565b905080156132ef57811561321257818660010185815481106131f3576131f3615738565b90600052602060002001600082825461320c91906159c3565b90915550505b600086600201858154811061322957613229615738565b906000526020600020018190555061327088600201858154811061324f5761324f615738565b60009182526020909120600290910201546001600160a01b03168883613eda565b808a7f1ec92956b13869de207e232e60c65e35826c5e12b7fdc6d70b083b5a4fd26703898b60020188815481106132a9576132a9615738565b60009182526020909120600290910201546040516132e692916001600160a01b0316906001600160a01b0392831681529116602082015260400190565b60405180910390a35b505050806132fc90615764565b90506130bc565b600084815260066020908152604080832060078352818420878552909252918290206003548454935163d7aee3bd60e01b8152929391926001600160a01b039182169263d7aee3bd9261337f929116907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a480908b90600401615a12565b60206040518083038186803b15801561339757600080fd5b505afa1580156133ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cf9190615aba565b6134105760405162461bcd60e51b81526020600482015260126024820152711a9bda5b8e881a5b9d985b1a59081c1bdbdb60721b604482015260640161087e565b8315801590613423575081600101548411155b6134635760405162461bcd60e51b81526020600482015260116024820152706a6f696e3a20696e76616c6964206c697160781b604482015260640161087e565b6003548354604051632106297960e11b81526001600160a01b039283169263420c52f2926134ba929116907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a480908b90600401615a12565b60206040518083038186803b1580156134d257600080fd5b505afa1580156134e6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061350a919061598f565b81546001600160801b0319166001600160801b039190911617815560028301546001600160401b0381111561354157613541615824565b60405190808252806020026020018201604052801561356a578160200160208202803683370190505b508051613581916001840191602090910190615098565b5060028301546001600160401b0381111561359e5761359e615824565b6040519080825280602002602001820160405280156135c7578160200160208202803683370190505b5080516135de916002840191602090910190615098565b5060028301546001600160401b038111156135fb576135fb615824565b604051908082528060200260200182016040528015613624578160200160208202803683370190505b50805161363b916003840191602090910190615098565b506003830154156136f05760035460405163528ee47960e11b81526001600160a01b037f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48081166004830152602482018990529091169063a51dc8f29060440160206040518083038186803b1580156136b257600080fd5b505afa1580156136c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136ea9190615a82565b60048201555b6005810184905560048301805490600061370983615764565b909155505060008681526008602052604090206137269086614ab8565b6137725760405162461bcd60e51b815260206004820152601760248201527f4661696c20746f20616464206a6f696e6564506f6f6c73000000000000000000604482015260640161087e565b8385877f5d48292d83151281e6ea967de9fd35716c713dc76c11beb42d78ed5110270f7360405160405180910390a4505050505050565b60008481526006602090815260408083206007835281842087855290925290912083158015906137eb5750600182015460058201546137e890866159c3565b11155b61382b5760405162461bcd60e51b815260206004820152601160248201527073796e633a20696e76616c6964206c697160781b604482015260640161087e565b60006138378787612d81565b905060005b60028501548110156139815760006138678460050154876002018481548110612c5657612c56615738565b905080156138e1578084600301838154811061388557613885615738565b90600052602060002001600082825461389e91906159c3565b92505081905550808660020183815481106138bb576138bb615738565b906000526020600020906002020160010160008282546138db91906159ac565b90915550505b60006138fb85600301848154811061317b5761317b615738565b9050801561396e578085600101848154811061391957613919615738565b90600052602060002001600082825461393291906159c3565b925050819055508085600201848154811061394f5761394f615738565b90600052602060002001600082825461396891906159c3565b90915550505b50508061397a90615764565b905061383c565b508060a0015184600101600082825461399a91906159c3565b9091555050805182546001600160801b0319166001600160801b0390911617825560048201546020820151600386015460058501546139dd93929190898c614ac4565b8260040181905550848260050160008282546139f991906159c3565b90915550506040518590879089907ff31cd5db84a4ab16cd339c510d5a60c63ef5818c538aa67046f5bc0dca794cd390600090a450505050505050565b6000611ef9825490565b6000613a4c8383614be6565b9392505050565b600b5460ff1615613a9f5760405162461bcd60e51b8152602060048201526016602482015275139bdd08185b1b1bddd959081d1bc819195c1bdcda5d60521b604482015260640161087e565b8015613b51578260045411613ac65760405162461bcd60e51b815260040161087e90615966565b600083815260056020526040902054429063ffffffff808316600160a01b9092041611801590613b14575060008481526005602052604090205463ffffffff600160c01b9091048116908216105b613b4f5760405162461bcd60e51b815260206004820152600c60248201526b496e76616c69642074696d6560a01b604482015260640161087e565b505b3360005b8351811015613ed357600a6000858381518110613b7457613b74615738565b60209081029190910181015182528101919091526040016000205460ff1615613bd85760405162461bcd60e51b8152602060048201526016602482015275139bdd08185b1b1bddd959081d1bc819195c1bdcda5d60521b604482015260640161087e565b613c28848281518110613bed57613bed615738565b602002602001015160096000856001600160a01b03166001600160a01b03168152602001908152602001600020614ab890919063ffffffff16565b613c3157600080fd5b7f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4806001600160a01b03166323b872dd8330878581518110613c7457613c74615738565b60200260200101516040518463ffffffff1660e01b8152600401613c9a93929190615a12565b600060405180830381600087803b158015613cb457600080fd5b505af1158015613cc8573d6000803e3d6000fd5b50505050838181518110613cde57613cde615738565b60200260200101517fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c83604051613d2491906001600160a01b0391909116815260200190565b60405180910390a28160066000868481518110613d4357613d43615738565b6020908102919091018101518252810191909152604001600090812080546001600160a01b0319166001600160a01b03938416179055600354865191921690635c6d96a9907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48090889086908110613dbc57613dbc615738565b60200260200101516040518363ffffffff1660e01b8152600401613df59291906001600160a01b03929092168252602082015260400190565b60206040518083038186803b158015613e0d57600080fd5b505afa158015613e21573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e45919061598f565b9050806001600160801b031660066000878581518110613e6757613e67615738565b60200260200101518152602001908152602001600020600101819055508315613eca57613eca858381518110613e9f57613e9f615738565b602002602001015187836001600160801b0316600560008b8152602001908152602001600020613303565b50600101613b55565b5050505050565b6001600160a01b038316613f91576000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114613f35576040519150601f19603f3d011682016040523d82523d6000602084013e613f3a565b606091505b5050905080613f8b5760405162461bcd60e51b815260206004820152601c60248201527f7472616e736665722072657761726420746f6b656e206661696c656400000000604482015260640161087e565b50505050565b613fa56001600160a01b0384168383614c10565b505050565b600083815260056020908152604080832087845260068352818420546007845282852088865290935292206001600160a01b03909116903382148061401c57508254600160c01b900463ffffffff164263ffffffff1611801561401c57503360009081526002602052604090205460ff165b6140725760405162461bcd60e51b815260206004820152602160248201527f657869743a206e6f74206f776e6572206f7220706f6f6c206e6f7420656e64656044820152601960fa1b606482015260840161087e565b600581015485158015906140865750808611155b6140c65760405162461bcd60e51b8152602060048201526011602482015270657869743a20696e76616c6964206c697160781b604482015260640161087e565b60006140d287836159ac565b905060006140e08a8a612d81565b90508060a001518660010160008282546140fa91906159c3565b9091555050805184546001600160801b0319166001600160801b039091161784556005840182905560005b600287015481101561439957600061414c85896002018481548110612c5657612c56615738565b905080156141c6578086600301838154811061416a5761416a615738565b90600052602060002001600082825461418391906159c3565b92505081905550808860020183815481106141a0576141a0615738565b906000526020600020906002020160010160008282546141c091906159ac565b90915550505b60006142058760030184815481106141e0576141e0615738565b90600052602060002001548560400151896001018681548110612cc357612cc3615738565b9050600087600201848154811061421e5761421e615738565b9060005260206000200154905081600014614275578188600101858154811061424957614249615738565b90600052602060002001600082825461426291906159c3565b90915550614272905082826159c3565b90505b8015614385578a1561436257600088600201858154811061429857614298615738565b90600052602060002001819055506142df8a60020185815481106142be576142be615738565b60009182526020909120600290910201546001600160a01b03168a83613eda565b808e7f1ec92956b13869de207e232e60c65e35826c5e12b7fdc6d70b083b5a4fd267038b8d600201888154811061431857614318615738565b600091825260209091206002909102015460405161435592916001600160a01b0316906001600160a01b0392831681529116602082015260400190565b60405180910390a3614385565b8088600201858154811061437857614378615738565b6000918252602090912001555b5050508061439290615764565b9050614125565b508161447b5760008a81526007602090815260408083208c8452909152812080546001600160801b0319168155906143d46001830182615077565b6143e2600283016000615077565b6143f0600383016000615077565b5060006004828101829055600590920181905590870180549161441283615ad7565b909155505060008a815260086020526040902061442f908a6144c0565b61447b5760405162461bcd60e51b815260206004820152601a60248201527f4661696c20746f2072656d6f7665206a6f696e6564506f6f6c73000000000000604482015260640161087e565b60405133815288908a908c907f275029c7b988945c03ac5499c0d532fce79ce36efab42e1b3f180a62001cad2c9060200160405180910390a450505050505050505050565b6000613a4c8383614c62565b60606000613a4c83614d55565b801561457b57604051630c479e6560e21b8152600481018490527f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4806001600160a01b03169063311e799490602401602060405180830381600087803b15801561454157600080fd5b505af1158015614555573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145799190615a82565b505b60408051608081018252848152600060208201818152828401918252606083018681529351637686c6e960e11b815283516004820152905160248201529051604482015291516064830152907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4806001600160a01b03169063ed0d8dd2906084015b606060405180830381600087803b15801561461657600080fd5b505af115801561462a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fe9190615aee565b7f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a480811561484a57866001600160a01b03167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031614156147795760405163bac37ef760e01b8152600481018690526001600160a01b03848116602483015282169063bac37ef790604401600060405180830381600087803b1580156146f957600080fd5b505af115801561470d573d6000803e3d6000fd5b505060405163bf1316c160e01b81526001600160a01b038416925063bf1316c1915061474190899088908890600401615b1c565b600060405180830381600087803b15801561475b57600080fd5b505af115801561476f573d6000803e3d6000fd5b5050505050614910565b856001600160a01b03167f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316141561484a5760405163bf1316c160e01b81526001600160a01b0382169063bf1316c1906147e3908a9089908890600401615b1c565b600060405180830381600087803b1580156147fd57600080fd5b505af1158015614811573d6000803e3d6000fd5b505060405163bac37ef760e01b8152600481018790526001600160a01b0386811660248301528416925063bac37ef79150604401614741565b60405163bf1316c160e01b81526001600160a01b0382169063bf1316c19061487a908a9089908890600401615b1c565b600060405180830381600087803b15801561489457600080fd5b505af11580156148a8573d6000803e3d6000fd5b505060405163bf1316c160e01b81526001600160a01b038416925063bf1316c191506148dc90899088908890600401615b1c565b600060405180830381600087803b1580156148f657600080fd5b505af115801561490a573d6000803e3d6000fd5b50505050505b505050505050565b6040805160a0810182528481526001600160801b03848116602083019081526000838501818152606085019182526080850187815295516398e04d7760e01b81528551600482015292519093166024830152915160448201529051606482015291516084830152907f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a4806001600160a01b0316906398e04d779060a4016145fc565b600082826149c78688615a9b565b6149d19190615a9b565b6149db9190615b55565b95945050505050565b60008064e8d4a510006149f78587615a9b565b614a019190615b55565b9050828111614a115760006149db565b6149db83826159ac565b600081614a2e575064e8d4a51000613a4c565b6000614a3a8486615b69565b90506149db83614a4f64e8d4a5100084615a9b565b614a599190615b55565b64e8d4a51000614db1565b60008084614a784263ffffffff1686614dc7565b614a8291906159ac565b90506000614a9482600160601b615a9b565b9050838111614aa4576000614aae565b614aae84826159ac565b9695505050505050565b6000613a4c8383614dde565b600084614ad357506000614aae565b600087614ae08789615b69565b12614af457614aef8688615b69565b614af6565b875b60035460405163528ee47960e11b81526001600160a01b037f000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48081166004830152602482018790529293506000929091169063a51dc8f29060440160206040518083038186803b158015614b6857600080fd5b505afa158015614b7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614ba09190615a82565b614baa9086615ba8565b614bb48388615ba8565b614bbe9190615c2d565b90506000614bcc86886159c3565b9050614bd88183615c6e565b9a9950505050505050505050565b6000826000018281548110614bfd57614bfd615738565b9060005260206000200154905092915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052613fa5908490614e2d565b60008181526001830160205260408120548015614d4b576000614c866001836159ac565b8554909150600090614c9a906001906159ac565b9050818114614cff576000866000018281548110614cba57614cba615738565b9060005260206000200154905080876000018481548110614cdd57614cdd615738565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614d1057614d10615c9c565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611ef9565b6000915050611ef9565b606081600001805480602002602001604051908101604052809291908181526020018280548015614da557602002820191906000526020600020905b815481526020019060010190808311614d91575b50505050509050919050565b600081831015614dc15782613a4c565b50919050565b600081831015614dd75781613a4c565b5090919050565b6000818152600183016020526040812054614e2557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611ef9565b506000611ef9565b6000614e82826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614eff9092919063ffffffff16565b805190915015613fa55780806020019051810190614ea09190615aba565b613fa55760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161087e565b6060614f0e8484600085614f16565b949350505050565b606082471015614f775760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161087e565b843b614fc55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161087e565b600080866001600160a01b03168587604051614fe19190615cde565b60006040518083038185875af1925050503d806000811461501e576040519150601f19603f3d011682016040523d82523d6000602084013e615023565b606091505b509150915061503382828661503e565b979650505050505050565b6060831561504d575081613a4c565b82511561505d5782518084602001fd5b8160405162461bcd60e51b815260040161087e9190615cfa565b508054600082559060005260206000209081019061509591906150e3565b50565b8280548282559060005260206000209081019282156150d3579160200282015b828111156150d35782518255916020019190600101906150b8565b506150df9291506150e3565b5090565b5b808211156150df57600081556001016150e4565b803563ffffffff8116811461510c57600080fd5b919050565b60008083601f84011261512357600080fd5b5081356001600160401b0381111561513a57600080fd5b6020830191508360208260051b850101111561515557600080fd5b9250929050565b60008060008060008060a0878903121561517557600080fd5b86359550615185602088016150f8565b9450615193604088016150f8565b935060608701356001600160401b038111156151ae57600080fd5b6151ba89828a01615111565b979a9699509497949695608090950135949350505050565b6001600160a01b038116811461509557600080fd5b6000602082840312156151f957600080fd5b8135613a4c816151d2565b6000806000806040858703121561521a57600080fd5b84356001600160401b038082111561523157600080fd5b61523d88838901615111565b9096509450602087013591508082111561525657600080fd5b5061526387828801615111565b95989497509550505050565b60006020828403121561528157600080fd5b5035919050565b600081518084526020808501945080840160005b838110156152b85781518752958201959082019060010161529c565b509495945050505050565b6001600160a01b03898116825263ffffffff8981166020808501919091529089166040840152606083018890526080830187905260a0830186905261010060c08401819052855190840181905260009261012085019287810192855b8181101561533d57845184168652948201949382019360010161531f565b505050505082810360e08401526153548185615288565b9b9a5050505050505050505050565b60008060008060006060868803121561537b57600080fd5b8535945060208601356001600160401b038082111561539957600080fd5b6153a589838a01615111565b909650945060408801359150808211156153be57600080fd5b506153cb88828901615111565b969995985093965092949392505050565b6000806000606084860312156153f157600080fd5b505081359360208301359350604090920135919050565b602081526000613a4c6020830184615288565b801515811461509557600080fd5b60006020828403121561543b57600080fd5b8135613a4c8161541b565b6000806020838503121561545957600080fd5b82356001600160401b0381111561546f57600080fd5b61547b85828601615111565b90969095509350505050565b60008060006040848603121561549c57600080fd5b8335925060208401356001600160401b038111156154b957600080fd5b6154c586828701615111565b9497909650939450505050565b600080604083850312156154e557600080fd5b82356154f0816151d2565b915060208301356155008161541b565b809150509250929050565b60008060008060008060008060c0898b03121561552757600080fd5b8835615532816151d2565b975061554060208a016150f8565b965061554e60408a016150f8565b955060608901356001600160401b038082111561556a57600080fd5b6155768c838d01615111565b909750955060808b013591508082111561558f57600080fd5b5061559c8b828c01615111565b999c989b50969995989497949560a00135949350505050565b600080604083850312156155c857600080fd5b50508035926020909101359150565b600080600080600080600060c0888a0312156155f257600080fd5b87356001600160401b0381111561560857600080fd5b6156148a828b01615111565b90985096505060208801359450604088013593506060880135615636816151d2565b925060808801356156468161541b565b8092505060a0880135905092959891949750929550565b6001600160801b038116811461509557600080fd5b600080600080600080600061010080898b03121561568f57600080fd5b8835975060208901356156a18161565d565b965060408901359550606089013594506080890135935060a08901356156c68161541b565b92508881018a10156156d757600080fd5b5060c08801905092959891949750929550565b8381526060602082015260006157036060830185615288565b8281036040840152614aae8185615288565b6020808252600990820152683337b93134b23232b760b91b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60006000198214156157785761577861574e565b5060010190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252600e908201526d0d2dcecc2d8d2c840d8cadccee8d60931b604082015260600190565b6000808335601e198436030181126157f557600080fd5b8301803591506001600160401b0382111561580f57600080fd5b60200191503681900382131561515557600080fd5b634e487b7160e01b600052604160045260246000fd5b604051602081016001600160401b038111828210171561585c5761585c615824565b60405290565b604051601f8201601f191681016001600160401b038111828210171561588a5761588a615824565b604052919050565b600060208083850312156158a557600080fd5b82356001600160401b03808211156158bc57600080fd5b81850191508282870312156158d057600080fd5b6158d861583a565b8235828111156158e757600080fd5b80840193505086601f8401126158fc57600080fd5b82358281111561590e5761590e615824565b8060051b925061591f858401615862565b818152928401850192858101908985111561593957600080fd5b948601945b848610156159575785358252948601949086019061593e565b83525090979650505050505050565b6020808252600f908201526e506f6f6c206e6f742065786973747360881b604082015260600190565b6000602082840312156159a157600080fd5b8151613a4c8161565d565b6000828210156159be576159be61574e565b500390565b600082198211156159d6576159d661574e565b500190565b60208082526018908201527f7370656369616c20666561747572652064697361626c65640000000000000000604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b600060208284031215615a4857600080fd5b8151613a4c816151d2565b60008060408385031215615a6657600080fd5b8251615a71816151d2565b6020840151909250615500816151d2565b600060208284031215615a9457600080fd5b5051919050565b6000816000190483118215151615615ab557615ab561574e565b500290565b600060208284031215615acc57600080fd5b8151613a4c8161541b565b600081615ae657615ae661574e565b506000190190565b600080600060608486031215615b0357600080fd5b8351925060208401519150604084015190509250925092565b6001600160a01b0393841681526020810192909252909116604082015260600190565b634e487b7160e01b600052601260045260246000fd5b600082615b6457615b64615b3f565b500490565b60008083128015600160ff1b850184121615615b8757615b8761574e565b6001600160ff1b0384018313811615615ba257615ba261574e565b50500390565b60006001600160ff1b0381841382841380821686840486111615615bce57615bce61574e565b600160ff1b6000871282811687830589121615615bed57615bed61574e565b60008712925087820587128484161615615c0957615c0961574e565b87850587128184161615615c1f57615c1f61574e565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615615c4f57615c4f61574e565b600160ff1b8390038412811615615c6857615c6861574e565b50500190565b600082615c7d57615c7d615b3f565b600160ff1b821460001984141615615c9757615c9761574e565b500590565b634e487b7160e01b600052603160045260246000fd5b60005b83811015615ccd578181015183820152602001615cb5565b83811115613f8b5750506000910152565b60008251615cf0818460208701615cb2565b9190910192915050565b6020815260008251806020840152615d19816040850160208701615cb2565b601f01601f1916919091016040019291505056fea164736f6c6343000809000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a48000000000000000000000000035be3f4fd8239a35a7f120756d4d69e5c5e10870
-----Decoded View---------------
Arg [0] : _nft (address): 0xe222fBE074A436145b255442D919E4E3A6c6a480
Arg [1] : _helper (address): 0x35BE3F4fd8239A35a7F120756D4D69e5C5e10870
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e222fbe074a436145b255442d919e4e3a6c6a480
Arg [1] : 00000000000000000000000035be3f4fd8239a35a7f120756d4d69e5c5e10870
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BSC | 33.12% | $0.41007 | 4,249.8978 | $1,742.76 | |
ARB | 9.59% | $0.409177 | 1,233.8507 | $504.86 | |
ARB | 8.15% | $3,041.65 | 0.141 | $428.96 | |
ARB | 3.21% | $0.594317 | 284.4387 | $169.05 | |
ARB | 1.04% | $0.465794 | 117.9732 | $54.95 | |
ARB | 0.36% | $3,354.8 | 0.00558657 | $18.74 | |
ARB | 0.20% | $1 | 10.4808 | $10.48 | |
OP | 18.27% | $1.28 | 749.9093 | $961.2 | |
OP | 0.50% | $3,353.09 | 0.00784124 | $26.29 | |
OP | 0.07% | $0.409042 | 8.4704 | $3.46 | |
MATIC | 15.84% | $3,353.09 | 0.2485 | $833.31 | |
MATIC | 2.38% | $0.409042 | 306.1352 | $125.22 | |
MATIC | <0.01% | $1.51 | 0.0716 | $0.1081 | |
BASE | 3.67% | $0.409042 | 471.676 | $192.94 | |
ETH | 2.48% | $0.407104 | 320.9995 | $130.68 | |
ETH | 0.53% | $3,355.74 | 0.00823924 | $27.65 | |
ETH | 0.51% | $2,956.8 | 0.00913038 | $27 | |
LINEA | 0.08% | $0.409717 | 10.3684 | $4.25 |
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.