Source Code
Overview
S Balance
0 S
Token Holdings
More Info
ContractCreator
Latest 6 from a total of 6 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Upkeep | 13578455 | 13 days ago | IN | 0 S | 0.0002299 | ||||
Set Receiver | 13578455 | 13 days ago | IN | 0 S | 0.00006075 | ||||
Set Reward Token... | 13578453 | 13 days ago | IN | 0 S | 0.00005196 | ||||
Add | 13577310 | 13 days ago | IN | 0 S | 0.00152335 | ||||
Set LM Pool Depl... | 13577212 | 13 days ago | IN | 0 S | 0.00003126 | ||||
Set LM Pool Depl... | 13568662 | 13 days ago | IN | 0 S | 0.00004902 |
Latest 16 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
13578455 | 13 days ago | 0 S | ||||
13578455 | 13 days ago | 0 S | ||||
13578455 | 13 days ago | 0 S | ||||
13578455 | 13 days ago | 0 S | ||||
13578455 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S | ||||
13577310 | 13 days ago | 0 S |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AlphaHunterV3
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 666 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "@openzeppelin/contracts/access/Ownable2Step.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./libraries/SafeCast.sol"; import "./interfaces/INonfungiblePositionManager.sol"; import "./interfaces/INonfungiblePositionManagerStruct.sol"; import "./interfaces/IStoryHuntV3Pool.sol"; import "./interfaces/IAlphaHunterV2.sol"; import "./interfaces/ILMPool.sol"; import "./interfaces/ILMPoolDeployer.sol"; import "./interfaces/IFarmBooster.sol"; import "./interfaces/IWIP.sol"; import "./utils/Multicall.sol"; import "./Enumerable.sol"; contract AlphaHunterV3 is INonfungiblePositionManagerStruct, Multicall, Ownable2Step, ReentrancyGuard, Enumerable { using SafeERC20 for IERC20; using SafeCast for uint256; struct PoolInfo { // V3 pool address IStoryHuntV3Pool v3Pool; // V3 pool token0 address address token0; // V3 pool token1 address address token1; // V3 pool fee uint24 fee; // total liquidity staking in the pool uint256 totalLiquidity; // total boost liquidity staking in the pool uint256 totalBoostLiquidity; } struct UserPositionInfo { uint128 liquidity; uint128 boostLiquidity; int24 tickLower; int24 tickUpper; address user; uint256 pid; uint256 boostMultiplier; } struct UserPositionReward { uint256 rewardGrowthInside; uint256 reward; } struct RewardInfo { /// @notice The reward token address. address token; /// @notice Total allocation points. Must be the sum of all pools' allocation points. uint256 totalAllocPoint; /// @notice Record the reward amount belong to AlphaHunterV3. uint256 rewardAmountBelongToMC; uint256 latestPeriodNumber; uint256 latestPeriodStartTime; uint256 latestPeriodEndTime; uint256 latestPeriodRewardPerSecond; } uint256 public poolLength; /// @notice Info of each MCV3 pool. mapping(uint256 => PoolInfo) public poolInfo; // mapping(tokenAddress => allocPoint) mapping(uint256 => mapping(address => uint256)) allocPoints; /// @notice userPositionInfos[tokenId] => UserPositionInfo /// @dev TokenId is unique, and we can query the pid by tokenId. mapping(uint256 => UserPositionInfo) public userPositionInfos; // mapping(tokenId => tokenAddress => reward) mapping(uint256 => mapping(address => UserPositionReward)) public userPositionRewards; /// @notice v3PoolPid[token0][token1][fee] => pid mapping(address => mapping(address => mapping(uint24 => uint256))) v3PoolPid; /// @notice v3PoolAddressPid[v3PoolAddress] => pid mapping(address => uint256) public v3PoolAddressPid; /// @notice Info of each reward token. mapping(address => RewardInfo) public rewardInfos; address[] public rewardTokens; /// @notice Address of WIP contract. address public immutable WIP; /// @notice Address of Receiver contract. address public receiver; INonfungiblePositionManager public immutable nonfungiblePositionManager; /// @notice Address of liquidity mining pool deployer contract. ILMPoolDeployer public LMPoolDeployer; /// @notice Address of farm booster contract. IFarmBooster public FARM_BOOSTER; /// @notice Only use for emergency situations. bool public emergency; /// @notice Address of the operator. address public operatorAddress; /// @notice Default period duration. uint256 public PERIOD_DURATION = 1 days; uint256 public constant MAX_DURATION = 30 days; uint256 public constant MIN_DURATION = 1 days; uint256 public constant PRECISION = 1e12; /// @notice Basic boost factor, none boosted user's boost factor uint256 public constant BOOST_PRECISION = 100 * 1e10; /// @notice Hard limit for maxmium boost factor, it must greater than BOOST_PRECISION uint256 public constant MAX_BOOST_PRECISION = 200 * 1e10; uint256 constant Q128 = 0x100000000000000000000000000000000; uint256 public constant MAX_REWARD_TOKENS = 3; error ZeroAddress(); error NotOwnerOrOperator(); error NoBalance(); error NotStoryHuntNFT(); error InvalidNFT(); error NotOwner(); error NoLiquidity(); error InvalidPeriodDuration(); error NoLMPool(); error InvalidPid(); error DuplicatedPool(uint256 pid); error NotEmpty(); error WrongReceiver(); error InconsistentAmount(); error InsufficientAmount(); error TooManyRewardTokens(); error RewardPeriodNotEnded(address token); event AddPool(uint256 indexed pid, uint256 allocPoint, IStoryHuntV3Pool indexed v3Pool, ILMPool indexed lmPool); event SetPool(uint256 indexed pid, uint256 allocPoint); event Deposit( address indexed from, uint256 indexed pid, uint256 indexed tokenId, uint256 liquidity, int24 tickLower, int24 tickUpper ); event Withdraw(address indexed from, address to, uint256 indexed pid, uint256 indexed tokenId); event UpdateLiquidity( address indexed from, uint256 indexed pid, uint256 indexed tokenId, int128 liquidity, int24 tickLower, int24 tickUpper ); event NewOperatorAddress(address operator); event NewLMPoolDeployerAddress(address deployer); event NewReceiver(address receiver); event NewPeriodDuration(uint256 periodDuration); event Harvest( address indexed sender, address to, address token, uint256 indexed pid, uint256 indexed tokenId, uint256 reward ); event NewUpkeepPeriod( address indexed token, uint256 indexed periodNumber, uint256 startTime, uint256 endTime, uint256 huntPerSecond, uint256 huntAmount ); event UpdateUpkeepPeriod( address indexed token, uint256 indexed periodNumber, uint256 oldEndTime, uint256 newEndTime, uint256 remainingHunt ); event UpdateFarmBoostContract(address indexed farmBoostContract); event SetEmergency(bool emergency); event RewardTokensAdded(address[] indexed tokens); modifier onlyOwnerOrOperator() { if (msg.sender != operatorAddress && msg.sender != owner()) revert NotOwnerOrOperator(); _; } modifier onlyValidPid(uint256 _pid) { if (_pid == 0 || _pid > poolLength) revert InvalidPid(); _; } modifier onlyReceiver() { require(receiver == msg.sender, "Not receiver"); _; } /** * @dev Throws if caller is not the boost contract. */ modifier onlyBoostContract() { require(address(FARM_BOOSTER) == msg.sender, "Not farm boost contract"); _; } /// @param _rewardTokens The list of reward token contract address. /// @param _nonfungiblePositionManager The NFT position manager contract address. /// @param _WIP The WIP token contract address. constructor(address[] memory _rewardTokens, INonfungiblePositionManager _nonfungiblePositionManager, address _WIP) { nonfungiblePositionManager = _nonfungiblePositionManager; WIP = _WIP; rewardTokens = _rewardTokens; for (uint256 i = 0; i < rewardTokens.length; i++) { rewardInfos[rewardTokens[i]].token = rewardTokens[i]; } } /// @notice Returns the reward per second, period end time. /// @param _token The reward token address. /// @param _pid The pool pid. /// @return rewardPerSecond Token reward per second. /// @return endTime Period end time. function getLatestPeriodInfoByPid( address _token, uint256 _pid ) public view returns (uint256 rewardPerSecond, uint256 endTime) { if (rewardInfos[_token].totalAllocPoint > 0) { rewardPerSecond = (rewardInfos[_token].latestPeriodRewardPerSecond * allocPoints[_pid][_token]) / rewardInfos[_token].totalAllocPoint; } endTime = rewardInfos[_token].latestPeriodEndTime; } /// @notice Returns the reward per second , period end time. This is for liquidity mining pool. /// @param _v3Pool Address of the V3 pool. /// @param _token The reward token address. /// @return rewardPerSecond Reward per second. /// @return endTime Period end time. function getLatestPeriodInfo( address _token, address _v3Pool ) public view returns (uint256 rewardPerSecond, uint256 endTime) { if (rewardInfos[_token].totalAllocPoint > 0) { rewardPerSecond = (rewardInfos[_token].latestPeriodRewardPerSecond * allocPoints[v3PoolAddressPid[_v3Pool]][_token]) / rewardInfos[_token].totalAllocPoint; } endTime = rewardInfos[_token].latestPeriodEndTime; } /// @notice View function for checking pending token rewards. /// @dev The pending token amount is based on the last state in LMPool. The actual amount will happen whenever liquidity changes or harvest. /// @param _tokenId Token Id of NFT. /// @param _token The reward token address. /// @return reward Pending reward. function pendingReward(address _token, uint256 _tokenId) external view returns (uint256 reward) { UserPositionInfo memory positionInfo = userPositionInfos[_tokenId]; if (positionInfo.pid != 0) { PoolInfo memory pool = poolInfo[positionInfo.pid]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) != address(0)) { uint256 rewardGrowthInside = LMPool.getRewardGrowthInside( _token, positionInfo.tickLower, positionInfo.tickUpper ); uint256 rewardGrowthInsideDelta; unchecked { rewardGrowthInsideDelta = rewardGrowthInside - userPositionRewards[_tokenId][_token].rewardGrowthInside; } reward = (rewardGrowthInsideDelta * positionInfo.boostLiquidity) / Q128; } reward += userPositionRewards[_tokenId][_token].reward; } } /// @notice For emergency use only. function setEmergency(bool _emergency) external onlyOwner { emergency = _emergency; emit SetEmergency(emergency); } function setReceiver(address _receiver) external onlyOwner { if (_receiver == address(0)) revert ZeroAddress(); for (uint i = 0; i < rewardTokens.length; i++) { if (IERC20(rewardTokens[i]).allowance(_receiver, address(this)) != type(uint256).max) revert(); } receiver = _receiver; emit NewReceiver(_receiver); } function setLMPoolDeployer(ILMPoolDeployer _LMPoolDeployer) external onlyOwner { if (address(_LMPoolDeployer) == address(0)) revert ZeroAddress(); LMPoolDeployer = _LMPoolDeployer; emit NewLMPoolDeployerAddress(address(_LMPoolDeployer)); } /// @dev set reward tokens, only owner can call this function function setRewardTokens(address[] memory _tokens) external onlyOwner { if (_tokens.length == 0) revert NotEmpty(); if (_tokens.length > MAX_REWARD_TOKENS) revert TooManyRewardTokens(); // Check if any current reward tokens are being removed and verify their periods have ended for (uint256 i = 0; i < rewardTokens.length; i++) { bool stillExists = false; for (uint256 j = 0; j < _tokens.length; j++) { if (rewardTokens[i] == _tokens[j]) { stillExists = true; break; } } // If token is being removed, verify its period has ended if (!stillExists) { RewardInfo memory rewardInfo = rewardInfos[rewardTokens[i]]; if (block.timestamp < rewardInfo.latestPeriodEndTime) { revert RewardPeriodNotEnded(rewardTokens[i]); } } } rewardTokens = _tokens; emit RewardTokensAdded(_tokens); } /// @notice Add a new pool. Can only be called by the owner. /// @notice One v3 pool can only create one pool. /// @param _allocPoint Number of allocation points for the new pool. /// @param _v3Pool Address of the V3 pool. /// @param _withUpdate Whether call "massUpdatePools" operation. function add(uint256 _allocPoint, IStoryHuntV3Pool _v3Pool, bool _withUpdate) external onlyOwner { if (_withUpdate) massUpdatePools(); ILMPool lmPool = LMPoolDeployer.deploy(_v3Pool); address token0 = _v3Pool.token0(); address token1 = _v3Pool.token1(); uint24 fee = _v3Pool.fee(); if (v3PoolPid[token0][token1][fee] != 0) revert DuplicatedPool(v3PoolPid[token0][token1][fee]); if (IERC20(token0).allowance(address(this), address(nonfungiblePositionManager)) == 0) IERC20(token0).safeApprove(address(nonfungiblePositionManager), type(uint256).max); if (IERC20(token1).allowance(address(this), address(nonfungiblePositionManager)) == 0) IERC20(token1).safeApprove(address(nonfungiblePositionManager), type(uint256).max); unchecked { poolLength++; } poolInfo[poolLength] = PoolInfo({ v3Pool: _v3Pool, token0: token0, token1: token1, fee: fee, totalLiquidity: 0, totalBoostLiquidity: 0 }); for (uint256 i = 0; i < rewardTokens.length; i++) { rewardInfos[rewardTokens[i]].totalAllocPoint += _allocPoint; allocPoints[poolLength][rewardTokens[i]] = _allocPoint; } v3PoolPid[token0][token1][fee] = poolLength; v3PoolAddressPid[address(_v3Pool)] = poolLength; emit AddPool(poolLength, _allocPoint, _v3Pool, lmPool); } /// @notice Update the given pool's CAKE allocation point. Can only be called by the owner. /// @param _pid The id of the pool. See `poolInfo`. /// @param _allocPoint New number of allocation points for the pool. /// @param _withUpdate Whether call "massUpdatePools" operation. function set(uint256 _pid, uint256 _allocPoint, bool _withUpdate) external onlyOwner onlyValidPid(_pid) { uint32 currentTime = uint32(block.timestamp); PoolInfo storage pool = poolInfo[_pid]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) != address(0)) { LMPool.accumulateReward(currentTime); } if (_withUpdate) massUpdatePools(); for (uint256 i = 0; i < rewardTokens.length; i++) { rewardInfos[rewardTokens[i]].totalAllocPoint = rewardInfos[rewardTokens[i]].totalAllocPoint - allocPoints[_pid][rewardTokens[i]] + _allocPoint; allocPoints[_pid][rewardTokens[i]] = _allocPoint; } emit SetPool(_pid, _allocPoint); } struct DepositCache { address token0; address token1; uint24 fee; int24 tickLower; int24 tickUpper; uint128 liquidity; } /// @notice Upon receiving a ERC721 function onERC721Received( address, address _from, uint256 _tokenId, bytes calldata ) external nonReentrant returns (bytes4) { if (msg.sender != address(nonfungiblePositionManager)) revert NotStoryHuntNFT(); DepositCache memory cache; ( , , cache.token0, cache.token1, cache.fee, cache.tickLower, cache.tickUpper, cache.liquidity, , , , ) = nonfungiblePositionManager.positions(_tokenId); if (cache.liquidity == 0) revert NoLiquidity(); uint256 pid = v3PoolPid[cache.token0][cache.token1][cache.fee]; if (pid == 0) revert InvalidNFT(); PoolInfo memory pool = poolInfo[pid]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) == address(0)) revert NoLMPool(); UserPositionInfo storage positionInfo = userPositionInfos[_tokenId]; positionInfo.tickLower = cache.tickLower; positionInfo.tickUpper = cache.tickUpper; positionInfo.user = _from; positionInfo.pid = pid; // Need to update LMPool. LMPool.accumulateReward(uint32(block.timestamp)); updateLiquidityOperation(positionInfo, _tokenId, 0); // Update Enumerable addToken(_from, _tokenId); emit Deposit(_from, pid, _tokenId, cache.liquidity, cache.tickLower, cache.tickUpper); return this.onERC721Received.selector; } function getRewardTokens() external view returns (address[] memory tokens) { tokens = rewardTokens; } /// @notice harvest token from pool. /// @param _token Token reward address. /// @param _tokenId Token Id of NFT. /// @param _to Address to. /// @return reward Token reward. function harvest(address _token, uint256 _tokenId, address _to) external nonReentrant returns (uint256 reward) { UserPositionInfo storage positionInfo = userPositionInfos[_tokenId]; if (positionInfo.user != msg.sender) revert NotOwner(); if (positionInfo.liquidity == 0 && userPositionRewards[_tokenId][_token].reward == 0) revert NoLiquidity(); reward = harvestOperation(positionInfo, _token, _tokenId, _to); } function harvestOperation( UserPositionInfo storage positionInfo, address _token, uint256 _tokenId, address _to ) internal returns (uint256 reward) { PoolInfo memory pool = poolInfo[positionInfo.pid]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) != address(0) && !emergency) { // Update rewardGrowthInside LMPool.accumulateReward(uint32(block.timestamp)); uint256 rewardGrowthInside = LMPool.getRewardGrowthInside( _token, positionInfo.tickLower, positionInfo.tickUpper ); uint256 rewardGrowthInsideDelta; unchecked { rewardGrowthInsideDelta = rewardGrowthInside - userPositionRewards[_tokenId][_token].rewardGrowthInside; } reward = (rewardGrowthInsideDelta * positionInfo.boostLiquidity) / Q128; userPositionRewards[_tokenId][_token].rewardGrowthInside = rewardGrowthInside; } reward += userPositionRewards[_tokenId][_token].reward; if (reward > 0) { if (_to != address(0)) { userPositionRewards[_tokenId][_token].reward = 0; _safeTransfer(_token, _to, reward); emit Harvest(msg.sender, _to, _token, positionInfo.pid, _tokenId, reward); } else { userPositionRewards[_tokenId][_token].reward = reward; } } } /// @notice Withdraw LP tokens from pool. /// @param _tokenId Token Id of NFT to deposit. /// @param _to Address to which NFT token to withdraw. /// @return reward Token reward. function withdraw(uint256 _tokenId, address _to) external nonReentrant returns (uint256 reward) { if (_to == address(this) || _to == address(0)) revert WrongReceiver(); UserPositionInfo storage positionInfo = userPositionInfos[_tokenId]; if (positionInfo.user != msg.sender) revert NotOwner(); for (uint256 i = 0; i < rewardTokens.length; i++) { reward += harvestOperation(positionInfo, rewardTokens[i], _tokenId, _to); } uint256 pid = positionInfo.pid; PoolInfo storage pool = poolInfo[pid]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) != address(0) && !emergency) { // Remove all liquidity from liquidity mining pool. int128 liquidityDelta = -int128(positionInfo.boostLiquidity); LMPool.updatePosition(positionInfo.tickLower, positionInfo.tickUpper, liquidityDelta); emit UpdateLiquidity( msg.sender, pid, _tokenId, liquidityDelta, positionInfo.tickLower, positionInfo.tickUpper ); } pool.totalLiquidity -= positionInfo.liquidity; pool.totalBoostLiquidity -= positionInfo.boostLiquidity; delete userPositionInfos[_tokenId]; // Update Enumerable removeToken(msg.sender, _tokenId); // Remove boosted token id in farm booster. if (address(FARM_BOOSTER) != address(0)) FARM_BOOSTER.removeBoostMultiplier(msg.sender, _tokenId, pid); nonfungiblePositionManager.safeTransferFrom(address(this), _to, _tokenId); emit Withdraw(msg.sender, _to, pid, _tokenId); } /// @notice Update liquidity for the NFT position. /// @param _tokenId Token Id of NFT to update. function updateLiquidity(uint256 _tokenId) external nonReentrant { UserPositionInfo storage positionInfo = userPositionInfos[_tokenId]; if (positionInfo.pid == 0) revert InvalidNFT(); for (uint256 i = 0; i < rewardTokens.length; i++) { harvestOperation(positionInfo, rewardTokens[i], _tokenId, address(0)); } updateLiquidityOperation(positionInfo, _tokenId, 0); } /// @notice Update farm boost multiplier for the NFT position. /// @param _tokenId Token Id of NFT to update. /// @param _newMultiplier New boost multiplier. function updateBoostMultiplier(uint256 _tokenId, uint256 _newMultiplier) external onlyBoostContract { UserPositionInfo storage positionInfo = userPositionInfos[_tokenId]; if (positionInfo.pid == 0) revert InvalidNFT(); for (uint256 i = 0; i < rewardTokens.length; i++) { harvestOperation(positionInfo, rewardTokens[i], _tokenId, address(0)); } updateLiquidityOperation(positionInfo, _tokenId, _newMultiplier); } function updateLiquidityOperation( UserPositionInfo storage positionInfo, uint256 _tokenId, uint256 _newMultiplier ) internal { (, , , , , int24 tickLower, int24 tickUpper, uint128 liquidity, , , , ) = nonfungiblePositionManager.positions( _tokenId ); PoolInfo storage pool = poolInfo[positionInfo.pid]; if (positionInfo.liquidity != liquidity) { pool.totalLiquidity = pool.totalLiquidity - positionInfo.liquidity + liquidity; positionInfo.liquidity = liquidity; } uint256 boostMultiplier = BOOST_PRECISION; if (address(FARM_BOOSTER) != address(0) && _newMultiplier == 0) { // Get the latest boostMultiplier and update boostMultiplier in farm booster. boostMultiplier = FARM_BOOSTER.updatePositionBoostMultiplier(_tokenId); } else if (_newMultiplier != 0) { // Update boostMultiplier from farm booster call. boostMultiplier = _newMultiplier; } if (boostMultiplier < BOOST_PRECISION) { boostMultiplier = BOOST_PRECISION; } else if (boostMultiplier > MAX_BOOST_PRECISION) { boostMultiplier = MAX_BOOST_PRECISION; } positionInfo.boostMultiplier = boostMultiplier; uint128 boostLiquidity = ((uint256(liquidity) * boostMultiplier) / BOOST_PRECISION).toUint128(); int128 liquidityDelta = int128(boostLiquidity) - int128(positionInfo.boostLiquidity); if (liquidityDelta != 0) { pool.totalBoostLiquidity = pool.totalBoostLiquidity - positionInfo.boostLiquidity + boostLiquidity; positionInfo.boostLiquidity = boostLiquidity; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) == address(0)) revert NoLMPool(); LMPool.updatePosition(tickLower, tickUpper, liquidityDelta); for (uint256 i = 0; i < rewardTokens.length; i++) { // Update latest rewardGrowthInside userPositionRewards[_tokenId][rewardTokens[i]].rewardGrowthInside = LMPool.getRewardGrowthInside( rewardTokens[i], tickLower, tickUpper ); } emit UpdateLiquidity(msg.sender, positionInfo.pid, _tokenId, liquidityDelta, tickLower, tickUpper); } } /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender` /// @param params tokenId The ID of the token for which liquidity is being increased, /// amount0Desired The desired amount of token0 to be spent, /// amount1Desired The desired amount of token1 to be spent, /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check, /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check, /// deadline The time by which the transaction must be included to effect the change /// @return liquidity The new liquidity amount as a result of the increase /// @return amount0 The amount of token0 to acheive resulting liquidity /// @return amount1 The amount of token1 to acheive resulting liquidity function increaseLiquidity( IncreaseLiquidityParams memory params ) external payable nonReentrant returns (uint128 liquidity, uint256 amount0, uint256 amount1) { UserPositionInfo storage positionInfo = userPositionInfos[params.tokenId]; if (positionInfo.pid == 0) revert InvalidNFT(); PoolInfo storage pool = poolInfo[positionInfo.pid]; pay(pool.token0, params.amount0Desired); pay(pool.token1, params.amount1Desired); if (pool.token0 != WIP && pool.token1 != WIP && msg.value > 0) revert(); (liquidity, amount0, amount1) = nonfungiblePositionManager.increaseLiquidity{value: msg.value}(params); uint256 token0Left = params.amount0Desired - amount0; uint256 token1Left = params.amount1Desired - amount1; if (token0Left > 0) { refund(pool.token0, token0Left); } if (token1Left > 0) { refund(pool.token1, token1Left); } for (uint256 i = 0; i < rewardTokens.length; i++) { harvestOperation(positionInfo, rewardTokens[i], params.tokenId, address(0)); } updateLiquidityOperation(positionInfo, params.tokenId, 0); } /// @notice Pay. /// @param _token The token to pay /// @param _amount The amount to pay function pay(address _token, uint256 _amount) internal { if (_token == WIP && msg.value > 0) { if (msg.value != _amount) revert InconsistentAmount(); } else { IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount); } } /// @notice Refund. /// @param _token The token to refund /// @param _amount The amount to refund function refund(address _token, uint256 _amount) internal { if (_token == WIP && msg.value > 0) { nonfungiblePositionManager.refundIP(); safeTransferIP(msg.sender, address(this).balance); } else { IERC20(_token).safeTransfer(msg.sender, _amount); } } /// @notice Decreases the amount of liquidity in a position and accounts it to the position /// @param params tokenId The ID of the token for which liquidity is being decreased, /// amount The amount by which liquidity will be decreased, /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, /// deadline The time by which the transaction must be included to effect the change /// @return amount0 The amount of token0 accounted to the position's tokens owed /// @return amount1 The amount of token1 accounted to the position's tokens owed function decreaseLiquidity( DecreaseLiquidityParams memory params ) external nonReentrant returns (uint256 amount0, uint256 amount1) { UserPositionInfo storage positionInfo = userPositionInfos[params.tokenId]; if (positionInfo.user != msg.sender) revert NotOwner(); (amount0, amount1) = nonfungiblePositionManager.decreaseLiquidity(params); for (uint256 i = 0; i < rewardTokens.length; i++) { harvestOperation(positionInfo, rewardTokens[i], params.tokenId, address(0)); } updateLiquidityOperation(positionInfo, params.tokenId, 0); } /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient /// @param params tokenId The ID of the NFT for which tokens are being collected, /// recipient The account that should receive the tokens, /// @dev Warning!!! Please make sure to use multicall to call unwrapWIP9 or sweepToken when set recipient address(0), or you will lose your funds. /// amount0Max The maximum amount of token0 to collect, /// amount1Max The maximum amount of token1 to collect /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect(CollectParams memory params) external nonReentrant returns (uint256 amount0, uint256 amount1) { UserPositionInfo storage positionInfo = userPositionInfos[params.tokenId]; if (positionInfo.user != msg.sender) revert NotOwner(); if (params.recipient == address(0)) params.recipient = address(this); (amount0, amount1) = nonfungiblePositionManager.collect(params); } /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient, then refund. /// @param params CollectParams. /// @param to Refund recipent. /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collectTo( CollectParams memory params, address to ) external nonReentrant returns (uint256 amount0, uint256 amount1) { UserPositionInfo storage positionInfo = userPositionInfos[params.tokenId]; if (positionInfo.user != msg.sender) revert NotOwner(); if (params.recipient == address(0)) params.recipient = address(this); (amount0, amount1) = nonfungiblePositionManager.collect(params); // Need to refund token to user when recipient is zero address if (params.recipient == address(this)) { PoolInfo storage pool = poolInfo[positionInfo.pid]; if (to == address(0)) to = msg.sender; transferToken(pool.token0, to); transferToken(pool.token1, to); } } /// @notice Transfer token from AlphaHunter V3. /// @param _token The token to transfer. /// @param _to The to address. function transferToken(address _token, address _to) internal { uint256 balance = IERC20(_token).balanceOf(address(this)); // Need to reduce rewardAmountBelongToMC. for (uint256 i = 0; i < rewardTokens.length; i++) { if (_token == rewardTokens[i]) { unchecked { // In fact balance should always be greater than or equal to rewardAmountBelongToMC // but in order to avoid any unknown issue, we added this check. if (balance >= rewardInfos[_token].rewardAmountBelongToMC) { balance -= rewardInfos[_token].rewardAmountBelongToMC; } else { // This should never happend. rewardInfos[_token].rewardAmountBelongToMC = balance; balance = 0; } } } if (balance > 0) { if (_token == WIP) { IWIP(WIP).withdraw(balance); safeTransferIP(_to, balance); } else { IERC20(_token).safeTransfer(_to, balance); } } } } /// @notice Unwraps the contract's WIP9 balance and sends it to recipient as IP. /// @dev The amountMinimum parameter prevents malicious contracts from stealing WIP9 from users. /// @param amountMinimum The minimum amount of WIP9 to unwrap /// @param recipient The address receiving IP function unwrapWIP9(uint256 amountMinimum, address recipient) external nonReentrant { uint256 balanceWIP = IWIP(WIP).balanceOf(address(this)); if (balanceWIP < amountMinimum) revert InsufficientAmount(); if (balanceWIP > 0) { IWIP(WIP).withdraw(balanceWIP); safeTransferIP(recipient, balanceWIP); } } /// @notice Transfers the full amount of a token held by this contract to recipient /// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users /// @param token The contract address of the token which will be transferred to `recipient` /// @param amountMinimum The minimum amount of token required for a transfer /// @param recipient The destination address of the token function sweepToken(address token, uint256 amountMinimum, address recipient) external nonReentrant { uint256 balanceToken = IERC20(token).balanceOf(address(this)); // Need to reduce rewardAmountBelongToMC. for (uint256 i = 0; i < rewardTokens.length; i++) { if (token == rewardTokens[i]) { unchecked { // In fact balance should always be greater than or equal to rewardAmountBelongToMC, but in order to avoid any unknown issue, we added this check. if (balanceToken >= rewardInfos[token].rewardAmountBelongToMC) { balanceToken -= rewardInfos[token].rewardAmountBelongToMC; } else { // This should never happend. rewardInfos[token].rewardAmountBelongToMC = balanceToken; balanceToken = 0; } } } if (balanceToken < amountMinimum) revert InsufficientAmount(); if (balanceToken > 0) { IERC20(token).safeTransfer(recipient, balanceToken); } } } /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens /// must be collected first. /// @param _tokenId The ID of the token that is being burned function burn(uint256 _tokenId) external nonReentrant { UserPositionInfo storage positionInfo = userPositionInfos[_tokenId]; if (positionInfo.user != msg.sender) revert NotOwner(); if (positionInfo.liquidity > 0) revert NotEmpty(); delete userPositionInfos[_tokenId]; // Update Enumerable removeToken(msg.sender, _tokenId); // Remove boosted token id in farm booster. if (address(FARM_BOOSTER) != address(0)) FARM_BOOSTER.removeBoostMultiplier(msg.sender, _tokenId, positionInfo.pid); nonfungiblePositionManager.burn(_tokenId); emit Withdraw(msg.sender, address(0), positionInfo.pid, _tokenId); } /// @notice Upkeep period. /// @param _token The token address. /// @param _amount The amount of reward injected. /// @param _duration The period duration. /// @param _withUpdate Whether call "massUpdatePools" operation. function upkeep(address _token, uint256 _amount, uint256 _duration, bool _withUpdate) external onlyReceiver { // Transfer reward token from receiver. IERC20(_token).safeTransferFrom(receiver, address(this), _amount); // Update rewardAmountBelongToMC unchecked { rewardInfos[_token].rewardAmountBelongToMC += _amount; } if (_withUpdate) massUpdatePools(); uint256 duration = PERIOD_DURATION; // Only use the _duration when _duration is between MIN_DURATION and MAX_DURATION. if (_duration >= MIN_DURATION && _duration <= MAX_DURATION) duration = _duration; uint256 currentTime = block.timestamp; uint256 endTime = currentTime + duration; uint256 rewardPerSecond; uint256 rewardAmount = _amount; if (rewardInfos[_token].latestPeriodEndTime > currentTime) { uint256 remainingReward = ((rewardInfos[_token].latestPeriodEndTime - currentTime) * rewardInfos[_token].latestPeriodRewardPerSecond) / PRECISION; emit UpdateUpkeepPeriod( _token, rewardInfos[_token].latestPeriodNumber, rewardInfos[_token].latestPeriodEndTime, currentTime, remainingReward ); rewardAmount += remainingReward; } rewardPerSecond = (rewardAmount * PRECISION) / duration; unchecked { rewardInfos[_token].latestPeriodNumber++; rewardInfos[_token].latestPeriodStartTime = currentTime + 1; rewardInfos[_token].latestPeriodEndTime = endTime; rewardInfos[_token].latestPeriodRewardPerSecond = rewardPerSecond; } emit NewUpkeepPeriod( _token, rewardInfos[_token].latestPeriodNumber, currentTime + 1, endTime, rewardPerSecond, rewardAmount ); } /// @notice Update reward for all the liquidity mining pool. function massUpdatePools() internal { uint32 currentTime = uint32(block.timestamp); for (uint256 pid = 1; pid <= poolLength; pid++) { PoolInfo storage pool = poolInfo[pid]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) != address(0)) { LMPool.accumulateReward(currentTime); } } } /// @notice Update hunt reward for the liquidity mining pool. /// @dev Avoid too many pools, and a single transaction cannot be fully executed for all pools. function updatePools(uint256[] calldata pids) external onlyOwnerOrOperator { uint32 currentTime = uint32(block.timestamp); for (uint256 i = 0; i < pids.length; i++) { PoolInfo storage pool = poolInfo[pids[i]]; ILMPool LMPool = ILMPool(pool.v3Pool.lmPool()); if (address(LMPool) != address(0)) { LMPool.accumulateReward(currentTime); } } } /// @notice Set operator address. /// @dev Callable by owner /// @param _operatorAddress New operator address. function setOperator(address _operatorAddress) external onlyOwner { if (_operatorAddress == address(0)) revert ZeroAddress(); operatorAddress = _operatorAddress; emit NewOperatorAddress(_operatorAddress); } /// @notice Set period duration. /// @dev Callable by owner /// @param _periodDuration New period duration. function setPeriodDuration(uint256 _periodDuration) external onlyOwner { if (_periodDuration < MIN_DURATION || _periodDuration > MAX_DURATION) revert InvalidPeriodDuration(); PERIOD_DURATION = _periodDuration; emit NewPeriodDuration(_periodDuration); } /// @notice Update farm boost contract address. /// @param _newFarmBoostContract The new farm booster address. function updateFarmBoostContract(address _newFarmBoostContract) external onlyOwner { // farm booster can be zero address when need to remove farm booster FARM_BOOSTER = IFarmBooster(_newFarmBoostContract); emit UpdateFarmBoostContract(_newFarmBoostContract); } /** * @notice Transfer IP in a safe way * @param to: address to transfer IP to * @param value: IP amount to transfer (in wei) */ function safeTransferIP(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(""); if (!success) revert(); } /// @notice Safe Transfer token reward. /// @param _token The token address. /// @param _to The reward receiver address. /// @param _amount Transfer reward amounts. function _safeTransfer(address _token, address _to, uint256 _amount) internal { if (_amount > 0) { uint256 balance = IERC20(_token).balanceOf(address(this)); if (balance < _amount) { _amount = balance; } // Update huntAmountBelongToMC unchecked { if (rewardInfos[_token].rewardAmountBelongToMC >= _amount) { rewardInfos[_token].rewardAmountBelongToMC -= _amount; } else { rewardInfos[_token].rewardAmountBelongToMC = balance - _amount; } } IERC20(_token).safeTransfer(_to, _amount); } } receive() external payable { if (msg.sender != address(nonfungiblePositionManager) && msg.sender != WIP) revert(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol) pragma solidity ^0.8.0; import "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) 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 making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value)); } /** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ function forceApprove(IERC20 token, address spender, uint256 value) internal { bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value); if (!_callOptionalReturnBool(token, approvalCall)) { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, approvalCall); } } /** * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`. * Revert on invalid signature. */ function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) 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`. * * 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; /** * @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 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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * 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 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 the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) 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: GPL-2.0-or-later pragma solidity ^0.8.10; /** * @notice This codes were copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/extensions/ERC721Enumerable.sol, and did some changes. * @dev This implements an optional extension of defined in the EIP that adds * enumerability of all the token ids in the contract as well as all token ids owned by each * account. */ abstract contract Enumerable { // Mapping owner address to token count mapping(address => uint256) private _balances; // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) { require(index < _balances[owner], "Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } function balanceOf(address owner) public view returns (uint256) { require(owner != address(0), "Enumerable: address zero is not a valid owner"); return _balances[owner]; } function addToken(address from, uint256 tokenId) internal { _addTokenToOwnerEnumeration(from, tokenId); unchecked { _balances[from] += 1; } } function removeToken(address from, uint256 tokenId) internal { _removeTokenFromOwnerEnumeration(from, tokenId); unchecked { _balances[from] -= 1; } } /** * @dev Private function to add a token to this extension's ownership-tracking data structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = _balances[to]; _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _balances[from] - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; require(tokenId == _ownedTokens[from][tokenIndex], "Invalid tokenId"); // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; interface IAlphaHunterV2 { function deposit(uint256 _pid, uint256 _amount) external; function withdraw(uint256 _pid, uint256 _amount) external; function pendingHunt(uint256 _pid, address _user) external view returns (uint256); function userInfo(uint256 _pid, address _user) external view returns (uint256, uint256, uint256); function emergencyWithdraw(uint256 _pid) external; function updateBoostMultiplier(address _user, uint256 _pid, uint256 _newBoostMulti) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; interface IFarmBooster { function getUserMultiplier(uint256 _tokenId) external view returns (uint256); function whiteList(uint256 _pid) external view returns (bool); function updatePositionBoostMultiplier(uint256 _tokenId) external returns (uint256 _multiplier); function removeBoostMultiplier(address _user, uint256 _tokenId, uint256 _pid) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; interface ILMPool { function updatePosition(int24 tickLower, int24 tickUpper, int128 liquidityDelta) external; function getRewardGrowthInside( address token, int24 tickLower, int24 tickUpper ) external view returns (uint256 rewardGrowthInsideX128); function accumulateReward(uint32 currTimestamp) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "./IStoryHuntV3Pool.sol"; import "./ILMPool.sol"; interface ILMPoolDeployer { function deploy(IStoryHuntV3Pool pool) external returns (ILMPool lmPool); }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.10; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "./INonfungiblePositionManagerStruct.sol"; interface INonfungiblePositionManager is INonfungiblePositionManagerStruct, IERC721 { /// @notice Returns the position information associated with a given token ID. /// @dev Throws if the token ID is not valid. /// @param tokenId The ID of the token that represents the position /// @return nonce The nonce for permits /// @return operator The address that is approved for spending /// @return token0 The address of the token0 for a specific pool /// @return token1 The address of the token1 for a specific pool /// @return fee The fee associated with the pool /// @return tickLower The lower end of the tick range for the position /// @return tickUpper The higher end of the tick range for the position /// @return liquidity The liquidity of the position /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation function positions( uint256 tokenId ) external view returns ( uint96 nonce, address operator, address token0, address token1, uint24 fee, int24 tickLower, int24 tickUpper, uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender` /// @param params tokenId The ID of the token for which liquidity is being increased, /// amount0Desired The desired amount of token0 to be spent, /// amount1Desired The desired amount of token1 to be spent, /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check, /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check, /// deadline The time by which the transaction must be included to effect the change /// @return liquidity The new liquidity amount as a result of the increase /// @return amount0 The amount of token0 to acheive resulting liquidity /// @return amount1 The amount of token1 to acheive resulting liquidity function increaseLiquidity( IncreaseLiquidityParams calldata params ) external payable returns (uint128 liquidity, uint256 amount0, uint256 amount1); /// @notice Decreases the amount of liquidity in a position and accounts it to the position /// @param params tokenId The ID of the token for which liquidity is being decreased, /// amount The amount by which liquidity will be decreased, /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity, /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity, /// deadline The time by which the transaction must be included to effect the change /// @return amount0 The amount of token0 accounted to the position's tokens owed /// @return amount1 The amount of token1 accounted to the position's tokens owed function decreaseLiquidity( DecreaseLiquidityParams calldata params ) external payable returns (uint256 amount0, uint256 amount1); /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient /// @param params tokenId The ID of the NFT for which tokens are being collected, /// recipient The account that should receive the tokens, /// amount0Max The maximum amount of token0 to collect, /// amount1Max The maximum amount of token1 to collect /// @return amount0 The amount of fees collected in token0 /// @return amount1 The amount of fees collected in token1 function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1); /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens /// must be collected first. /// @param tokenId The ID of the token that is being burned function burn(uint256 tokenId) external payable; function refundIP() external payable; }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.10; interface INonfungiblePositionManagerStruct { struct IncreaseLiquidityParams { uint256 tokenId; uint256 amount0Desired; uint256 amount1Desired; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct DecreaseLiquidityParams { uint256 tokenId; uint128 liquidity; uint256 amount0Min; uint256 amount1Min; uint256 deadline; } struct CollectParams { uint256 tokenId; address recipient; uint128 amount0Max; uint128 amount1Max; } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.10; interface IStoryHuntV3Pool { function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function fee() external view returns (uint24); function lmPool() external view returns (address); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /// @title Interface for WIP9 interface IWIP is IERC20 { /// @notice Deposit ether to get wrapped ether function deposit() external payable; /// @notice Withdraw wrapped ether to get ether function withdraw(uint256) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.10; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { require(value < 2 ** 128, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } }
// SPDX-License-Identifier: GPL-2.0-or-later pragma solidity ^0.8.10; /// @title Multicall /// @notice Enables calling multiple methods in a single call to the contract contract Multicall { function multicall(bytes[] calldata data) public payable returns (bytes[] memory results) { results = new bytes[](data.length); for (uint256 i = 0; i < data.length; i++) { (bool success, bytes memory result) = address(this).delegatecall(data[i]); if (!success) { // Next 5 lines from https://ethereum.stackexchange.com/a/83577 if (result.length < 68) revert(); assembly { result := add(result, 0x04) } revert(abi.decode(result, (string))); } results[i] = result; } } }
{ "optimizer": { "enabled": true, "runs": 666 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"inputs":[{"internalType":"address[]","name":"_rewardTokens","type":"address[]"},{"internalType":"contract INonfungiblePositionManager","name":"_nonfungiblePositionManager","type":"address"},{"internalType":"address","name":"_WIP","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"DuplicatedPool","type":"error"},{"inputs":[],"name":"InconsistentAmount","type":"error"},{"inputs":[],"name":"InsufficientAmount","type":"error"},{"inputs":[],"name":"InvalidNFT","type":"error"},{"inputs":[],"name":"InvalidPeriodDuration","type":"error"},{"inputs":[],"name":"InvalidPid","type":"error"},{"inputs":[],"name":"NoBalance","type":"error"},{"inputs":[],"name":"NoLMPool","type":"error"},{"inputs":[],"name":"NoLiquidity","type":"error"},{"inputs":[],"name":"NotEmpty","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotOwnerOrOperator","type":"error"},{"inputs":[],"name":"NotStoryHuntNFT","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"RewardPeriodNotEnded","type":"error"},{"inputs":[],"name":"TooManyRewardTokens","type":"error"},{"inputs":[],"name":"WrongReceiver","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IStoryHuntV3Pool","name":"v3Pool","type":"address"},{"indexed":true,"internalType":"contract ILMPool","name":"lmPool","type":"address"}],"name":"AddPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":false,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"deployer","type":"address"}],"name":"NewLMPoolDeployerAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"NewOperatorAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"periodDuration","type":"uint256"}],"name":"NewPeriodDuration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"NewReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"periodNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"huntPerSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"huntAmount","type":"uint256"}],"name":"NewUpkeepPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"RewardTokensAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"emergency","type":"bool"}],"name":"SetEmergency","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"}],"name":"SetPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"farmBoostContract","type":"address"}],"name":"UpdateFarmBoostContract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"int128","name":"liquidity","type":"int128"},{"indexed":false,"internalType":"int24","name":"tickLower","type":"int24"},{"indexed":false,"internalType":"int24","name":"tickUpper","type":"int24"}],"name":"UpdateLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"periodNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newEndTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingHunt","type":"uint256"}],"name":"UpdateUpkeepPeriod","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"BOOST_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FARM_BOOSTER","outputs":[{"internalType":"contract IFarmBooster","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LMPoolDeployer","outputs":[{"internalType":"contract ILMPoolDeployer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BOOST_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_REWARD_TOKENS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERIOD_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WIP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IStoryHuntV3Pool","name":"_v3Pool","type":"address"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"}],"internalType":"struct INonfungiblePositionManagerStruct.CollectParams","name":"params","type":"tuple"}],"name":"collect","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint128","name":"amount0Max","type":"uint128"},{"internalType":"uint128","name":"amount1Max","type":"uint128"}],"internalType":"struct INonfungiblePositionManagerStruct.CollectParams","name":"params","type":"tuple"},{"internalType":"address","name":"to","type":"address"}],"name":"collectTo","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","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":"struct INonfungiblePositionManagerStruct.DecreaseLiquidityParams","name":"params","type":"tuple"}],"name":"decreaseLiquidity","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergency","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_v3Pool","type":"address"}],"name":"getLatestPeriodInfo","outputs":[{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"getLatestPeriodInfoByPid","outputs":[{"internalType":"uint256","name":"rewardPerSecond","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokens","outputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"harvest","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount0Desired","type":"uint256"},{"internalType":"uint256","name":"amount1Desired","type":"uint256"},{"internalType":"uint256","name":"amount0Min","type":"uint256"},{"internalType":"uint256","name":"amount1Min","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct INonfungiblePositionManagerStruct.IncreaseLiquidityParams","name":"params","type":"tuple"}],"name":"increaseLiquidity","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nonfungiblePositionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"operatorAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"contract IStoryHuntV3Pool","name":"v3Pool","type":"address"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint24","name":"fee","type":"uint24"},{"internalType":"uint256","name":"totalLiquidity","type":"uint256"},{"internalType":"uint256","name":"totalBoostLiquidity","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardInfos","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"totalAllocPoint","type":"uint256"},{"internalType":"uint256","name":"rewardAmountBelongToMC","type":"uint256"},{"internalType":"uint256","name":"latestPeriodNumber","type":"uint256"},{"internalType":"uint256","name":"latestPeriodStartTime","type":"uint256"},{"internalType":"uint256","name":"latestPeriodEndTime","type":"uint256"},{"internalType":"uint256","name":"latestPeriodRewardPerSecond","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_emergency","type":"bool"}],"name":"setEmergency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ILMPoolDeployer","name":"_LMPoolDeployer","type":"address"}],"name":"setLMPoolDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_periodDuration","type":"uint256"}],"name":"setPeriodDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"}],"name":"setReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"setRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountMinimum","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"unwrapWIP9","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_newMultiplier","type":"uint256"}],"name":"updateBoostMultiplier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newFarmBoostContract","type":"address"}],"name":"updateFarmBoostContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"updateLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"updatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"bool","name":"_withUpdate","type":"bool"}],"name":"upkeep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPositionInfos","outputs":[{"internalType":"uint128","name":"liquidity","type":"uint128"},{"internalType":"uint128","name":"boostLiquidity","type":"uint128"},{"internalType":"int24","name":"tickLower","type":"int24"},{"internalType":"int24","name":"tickUpper","type":"int24"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"boostMultiplier","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userPositionRewards","outputs":[{"internalType":"uint256","name":"rewardGrowthInside","type":"uint256"},{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"v3PoolAddressPid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"reward","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60c0604052620151806013553480156200001857600080fd5b506040516200644b3803806200644b8339810160408190526200003b916200025d565b62000046336200012f565b60016002556001600160a01b0380831660a052811660805282516200007390600e906020860190620001a9565b5060005b600e548110156200012557600e818154811062000098576200009862000355565b9060005260206000200160009054906101000a90046001600160a01b0316600d6000600e8481548110620000d057620000d062000355565b6000918252602080832091909101546001600160a01b039081168452908301939093526040909101902080546001600160a01b03191692909116919091179055806200011c816200036b565b91505062000077565b5050505062000395565b600180546001600160a01b0319169055620001568162000159602090811b62003e6417901c565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b82805482825590600052602060002090810192821562000201579160200282015b828111156200020157825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190620001ca565b506200020f92915062000213565b5090565b5b808211156200020f576000815560010162000214565b634e487b7160e01b600052604160045260246000fd5b80516001600160a01b03811681146200025857600080fd5b919050565b6000806000606084860312156200027357600080fd5b83516001600160401b03808211156200028b57600080fd5b818601915086601f830112620002a057600080fd5b8151602082821115620002b757620002b76200022a565b8160051b604051601f19603f83011681018181108682111715620002df57620002df6200022a565b60405292835281830193508481018201928a841115620002fe57600080fd5b948201945b838610156200032757620003178662000240565b8552948201949382019362000303565b975062000338905088820162000240565b9550505050506200034c6040850162000240565b90509250925092565b634e487b7160e01b600052603260045260246000fd5b60006000198214156200038e57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a051615fe8620004636000396000818161037e01528181610acb015281816110c7015281816114fd0152818161169f015281816117a50152818161182f01528181611e9b01528181611f2101528181611f6501528181611feb015281816125be0152818161291201528181613de5015281816144840152614d7d0152600081816103b201528181610a27015281816124f501528181612531015281816138510152818161390301528181614ab701528181614b0501528181614cbc0152614d370152615fe86000f3fe60806040526004361061036e5760003560e01c806379ba5097116101c6578063caa6fea4116100f7578063eff7a11311610095578063f54ac2461161006f578063f54ac24614610c75578063f7260d3e14610c95578063fbc911d014610cb5578063fc6f786514610cd557600080fd5b8063eff7a11314610c15578063f2fde38b14610c35578063f430cf0d14610c5557600080fd5b8063cf242849116100d1578063cf24284914610b97578063cfb8ccfb14610bb7578063df2ab5bb14610bd7578063e30c397814610bf757600080fd5b8063caa6fea414610b46578063cc6db2da14610a49578063ced0911214610b7757600080fd5b8063ac9650d811610164578063b44a27221161013e578063b44a272214610ab9578063b4ce128014610aed578063b6a6d17714610b0d578063c4f59f9b14610b2457600080fd5b8063ac9650d814610a62578063b1724b4614610a82578063b3ab15fb14610a9957600080fd5b80637c2d6e01116101a05780637c2d6e01146109d75780638da5cb5b146109f75780639ba879cf14610a15578063aaf5eb6814610a4957600080fd5b806379ba5097146109825780637bb21b46146109975780637bb7bed1146109b757600080fd5b8063233a48a2116102a05780636558954f1161023e57806369b021281161021857806369b021281461091357806370a082311461092d578063715018a61461094d578063718da7ee1461096257600080fd5b80636558954f146108bd57806369746a1d146108d3578063699233c3146108f357600080fd5b806342966c681161027a57806342966c681461084857806344780994146108685780635d0cde971461088857806364482f791461089d57600080fd5b8063233a48a2146106c15780632f745c59146107625780633b1acf741461078257600080fd5b80630d55f9131161030d5780631526fe27116102e75780631526fe27146105a15780631eaaa04514610649578063201e81a814610669578063219f5d171461068957600080fd5b80630d55f91314610510578063127effb214610530578063150b7a021461056857600080fd5b8063070f3c0711610349578063070f3c071461048d5780630743384d146104ad578063081e3eda146104da5780630c49ccbe146104f057600080fd5b8062f714ce146103e65780630327ae47146104195780630501d5561461046d57600080fd5b366103e157336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015906103d55750336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614155b156103df57600080fd5b005b600080fd5b3480156103f257600080fd5b50610406610401366004615431565b610cf5565b6040519081526020015b60405180910390f35b34801561042557600080fd5b50610458610434366004615431565b600a6020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610410565b34801561047957600080fd5b506103df61048836600461546f565b611179565b34801561049957600080fd5b506103df6104a836600461548c565b6111ee565b3480156104b957600080fd5b506104066104c83660046154d6565b600c6020526000908152604090205481565b3480156104e657600080fd5b5061040660065481565b3480156104fc57600080fd5b5061045861050b36600461554f565b611467565b34801561051c57600080fd5b5061045861052b366004615648565b6115ec565b34801561053c57600080fd5b50601254610550906001600160a01b031681565b6040516001600160a01b039091168152602001610410565b34801561057457600080fd5b50610588610583366004615675565b611790565b6040516001600160e01b03199091168152602001610410565b3480156105ad57600080fd5b506106066105bc366004615714565b600760205260009081526040902080546001820154600283015460038401546004909401546001600160a01b039384169492841693821692600160a01b90920462ffffff16919086565b604080516001600160a01b0397881681529587166020870152939095169284019290925262ffffff166060830152608082015260a081019190915260c001610410565b34801561065557600080fd5b506103df61066436600461572d565b611c39565b34801561067557600080fd5b506103df61068436600461576f565b612238565b61069c610697366004615821565b61245c565b604080516001600160801b039094168452602084019290925290820152606001610410565b3480156106cd57600080fd5b506107236106dc3660046154d6565b600d6020526000908152604090208054600182015460028301546003840154600485015460058601546006909601546001600160a01b039095169593949293919290919087565b604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e001610410565b34801561076e57600080fd5b5061040661077d36600461589b565b61271d565b34801561078e57600080fd5b506107f761079d366004615714565b6009602052600090815260409020805460018201546002808401546003909401546001600160801b0380851695600160801b909504169383830b936301000000810490930b92600160301b90046001600160a01b03169187565b604080516001600160801b039889168152979096166020880152600294850b958701959095529190920b60608501526001600160a01b03909116608084015260a083015260c082015260e001610410565b34801561085457600080fd5b506103df610863366004615714565b6127bb565b34801561087457600080fd5b506103df61088336600461590c565b6129c1565b34801561089457600080fd5b50610406600381565b3480156108a957600080fd5b506103df6108b836600461594e565b612b47565b3480156108c957600080fd5b5061040660135481565b3480156108df57600080fd5b506103df6108ee36600461597c565b612e1f565b3480156108ff57600080fd5b5061045861090e36600461589b565b612f0d565b34801561091f57600080fd5b506104066501d1a94a200081565b34801561093957600080fd5b506104066109483660046154d6565b612fa7565b34801561095957600080fd5b506103df613041565b34801561096e57600080fd5b506103df61097d3660046154d6565b613055565b34801561098e57600080fd5b506103df61318f565b3480156109a357600080fd5b506104586109b236600461599e565b613206565b3480156109c357600080fd5b506105506109d2366004615714565b61327c565b3480156109e357600080fd5b506103df6109f2366004615714565b6132a6565b348015610a0357600080fd5b506000546001600160a01b0316610550565b348015610a2157600080fd5b506105507f000000000000000000000000000000000000000000000000000000000000000081565b348015610a5557600080fd5b5061040664e8d4a5100081565b610a75610a7036600461590c565b613314565b6040516104109190615a24565b348015610a8e57600080fd5b5061040662278d0081565b348015610aa557600080fd5b506103df610ab43660046154d6565b61346c565b348015610ac557600080fd5b506105507f000000000000000000000000000000000000000000000000000000000000000081565b348015610af957600080fd5b50601054610550906001600160a01b031681565b348015610b1957600080fd5b506104066201518081565b348015610b3057600080fd5b50610b396134e9565b6040516104109190615a86565b348015610b5257600080fd5b50601154610b6790600160a01b900460ff1681565b6040519015158152602001610410565b348015610b8357600080fd5b506103df610b92366004615714565b61354b565b348015610ba357600080fd5b506103df610bb23660046154d6565b6135ee565b348015610bc357600080fd5b506103df610bd23660046154d6565b61366b565b348015610be357600080fd5b506103df610bf2366004615ad3565b6136bd565b348015610c0357600080fd5b506001546001600160a01b0316610550565b348015610c2157600080fd5b506103df610c30366004615431565b613831565b348015610c4157600080fd5b506103df610c503660046154d6565b613980565b348015610c6157600080fd5b50610406610c7036600461589b565b6139f1565b348015610c8157600080fd5b50610406610c90366004615ad3565b613c6d565b348015610ca157600080fd5b50600f54610550906001600160a01b031681565b348015610cc157600080fd5b50601154610550906001600160a01b031681565b348015610ce157600080fd5b50610458610cf0366004615b0a565b613d32565b6000610cff613eb4565b6001600160a01b038216301480610d1d57506001600160a01b038216155b15610d3b57604051631964c57360e11b815260040160405180910390fd5b60008381526009602052604090206001810154600160301b90046001600160a01b03163314610d7d576040516330cd747160e01b815260040160405180910390fd5b60005b600e54811015610ddb57610dbd82600e8381548110610da157610da1615b26565b6000918252602090912001546001600160a01b03168787613f0c565b610dc79084615b52565b925080610dd381615b6a565b915050610d80565b506002810154600081815260076020908152604080832080548251630a81a92360e31b815292519194936001600160a01b039091169263540d491892600480830193928290030181865afa158015610e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5b9190615b95565b90506001600160a01b03811615801590610e7f5750601154600160a01b900460ff16155b15610f7f578354600090610ea290600160801b90046001600160801b0316615bb2565b6001860154604051638910faf160e01b8152600282810b6004830152630100000090920490910b6024820152600f82900b60448201529091506001600160a01b03831690638910faf190606401600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050600185015460408051600f84900b8152600283810b6020830152630100000090930490920b908201528890859033907fee8f6362d59839b4b3c990d7e085a63a0fe2c58f4eff4a9a2b6de93a4c645ae39060600160405180910390a4505b83546003830180546001600160801b0390921691600090610fa1908490615be2565b90915550508354600483018054600160801b9092046001600160801b031691600090610fce908490615be2565b9091555050600087815260096020526040812081815560018101805479ffffffffffffffffffffffffffffffffffffffffffffffffffff19169055600281018290556003015561101e338861426a565b6011546001600160a01b03161561109b5760115460405163622cd4e160e11b815233600482015260248101899052604481018590526001600160a01b039091169063c459a9c290606401600060405180830381600087803b15801561108257600080fd5b505af1158015611096573d6000803e3d6000fd5b505050505b604051632142170760e11b81523060048201526001600160a01b038781166024830152604482018990527f000000000000000000000000000000000000000000000000000000000000000016906342842e0e90606401600060405180830381600087803b15801561110b57600080fd5b505af115801561111f573d6000803e3d6000fd5b50506040516001600160a01b038916815289925085915033907ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb5679060200160405180910390a4505050506111736001600255565b92915050565b611181614296565b6011805474ff00000000000000000000000000000000000000001916600160a01b8315158102919091179182905560405160ff9190920416151581527fc749456be5379ac4cfc1f856208b32ddcf01b9db3ce6c37784ad91a8390ae9a8906020015b60405180910390a150565b600f546001600160a01b0316331461124d5760405162461bcd60e51b815260206004820152600c60248201527f4e6f74207265636569766572000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600f54611268906001600160a01b03868116911630866142f0565b6001600160a01b0384166000908152600d60205260409020600201805484019055801561129757611297614370565b6013546201518083108015906112b0575062278d008311155b156112b85750815b4260006112c58383615b52565b6001600160a01b0388166000908152600d60205260408120600501549192509087908410156113af576001600160a01b0389166000908152600d60205260408120600681015460059091015464e8d4a510009190611324908890615be2565b61132e9190615bf9565b6113389190615c18565b6001600160a01b038b166000818152600d6020908152604091829020600381015460059091015483519081529182018a9052918101849052929350917f220da7a534a80a110f7ff72f9922efb97f37355d49f903e0aaac1d19397458d19060600160405180910390a36113ab8183615b52565b9150505b846113bf64e8d4a5100083615bf9565b6113c99190615c18565b6001600160a01b038a166000818152600d6020526040902060038101805460019081019182905588810160048401556005830188905560069092018490559294507fadceb780601967fcb680db81d7a4540165bf0a39608785518a833a47683968cd90611437908890615b52565b604080519182526020820188905281018690526060810185905260800160405180910390a3505050505050505050565b600080611472613eb4565b825160009081526009602052604090206001810154600160301b90046001600160a01b031633146114b6576040516330cd747160e01b815260040160405180910390fd5b60408051630624e65f60e11b81528551600482015260208601516001600160801b0316602482015290850151604482015260608501516064820152608085015160848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690630c49ccbe9060a40160408051808303816000875af115801561154d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115719190615c3a565b909350915060005b600e548110156115cb576115b882600e838154811061159a5761159a615b26565b600091825260208220015488516001600160a01b0390911691613f0c565b50806115c381615b6a565b915050611579565b506115dc818560000151600061447d565b506115e76001600255565b915091565b6000806115f7613eb4565b835160009081526009602052604090206001810154600160301b90046001600160a01b0316331461163b576040516330cd747160e01b815260040160405180910390fd5b60208501516001600160a01b0316611654573060208601525b6040805163fc6f786560e01b81528651600482015260208701516001600160a01b039081166024830152918701516001600160801b03908116604483015260608801511660648201527f00000000000000000000000000000000000000000000000000000000000000009091169063fc6f78659060840160408051808303816000875af11580156116e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170d9190615c3a565b602087015191945092506001600160a01b031630141561177e57600281015460009081526007602052604090206001600160a01b03851661174c573394505b6001810154611764906001600160a01b03168661499c565b600281015461177c906001600160a01b03168661499c565b505b506117896001600255565b9250929050565b600061179a613eb4565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146117e3576040516314a5156160e21b815260040160405180910390fd5b6040805160c081018252600080825260208201819052818301819052606082018190526080820181905260a0820152905163133f757160e31b8152600481018690526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906399fbab889060240161018060405180830381865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190615c8e565b505050506001600160801b031660a08901819052600291820b60808a015291900b606088015262ffffff9190911660408701526001600160a01b0391821660208701529116845215159150611905905057604051636180f03f60e11b815260040160405180910390fd5b80516001600160a01b039081166000908152600b602090815260408083208286015190941683529281528282208385015162ffffff168352905220548061195f5760405163079f151f60e11b815260040160405180910390fd5b6000818152600760209081526040808320815160c08101835281546001600160a01b039081168083526001840154821683870152600284015491821683860152600160a01b90910462ffffff1660608301526003830154608083015260049283015460a08301528351630a81a92360e31b81529351919594909363540d49189381810193918290030181865afa1580156119fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a219190615b95565b90506001600160a01b038116611a4a5760405163ef3d9b2160e01b815260040160405180910390fd5b6000600960008a8152602001908152602001600020905084606001518160010160006101000a81548162ffffff021916908360020b62ffffff16021790555084608001518160010160036101000a81548162ffffff021916908360020b62ffffff160217905550898160010160066101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160020181905550816001600160a01b031663214a6fe2426040518263ffffffff1660e01b8152600401611b1b919063ffffffff91909116815260200190565b600060405180830381600087803b158015611b3557600080fd5b505af1158015611b49573d6000803e3d6000fd5b50505050611b59818a600061447d565b611bac8a8a6001600160a01b039190911660008181526003602081815260408084208054600484528286208187528452828620889055968552600583529084209590955592909152905280546001019055565b60a08501516060808701516080880151604080516001600160801b039095168552600292830b6020860152910b908301528a9186916001600160a01b038e16917fb19157bff94fdd40c58c7d4a5d52e8eb8c2d570ca17b322b49a2bbbeedc82fbf910160405180910390a450630a85bd0160e11b945050505050611c306001600255565b95945050505050565b611c41614296565b8015611c4f57611c4f614370565b601054604051634c96a38960e01b81526001600160a01b0384811660048301526000921690634c96a389906024016020604051808303816000875af1158015611c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc09190615b95565b90506000836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d269190615b95565b90506000846001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8c9190615b95565b90506000856001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df29190615d6f565b6001600160a01b038085166000908152600b60209081526040808320938716835292815282822062ffffff851683529052205490915015611e7e576001600160a01b038381166000908152600b60209081526040808320938616835292815282822062ffffff851683529052819020549051637d38f65f60e01b81526004810191909152602401611244565b604051636eb1769f60e11b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015284169063dd62ed3e90604401602060405180830381865afa158015611eea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0e9190615d8a565b611f4857611f486001600160a01b0384167f0000000000000000000000000000000000000000000000000000000000000000600019614b9e565b604051636eb1769f60e11b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015283169063dd62ed3e90604401602060405180830381865afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd89190615d8a565b612012576120126001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000600019614b9e565b600680546001908101918290556040805160c0810182526001600160a01b03808b168252878116602080840191825288831684860190815262ffffff808a166060870190815260006080880181815260a089018281529b82526007909552978820965187549087166001600160a01b0319918216178855945198870180549987169990951698909817909355516002850180549751909316600160a01b027fffffffffffffffffff0000000000000000000000000000000000000000000000909716931692909217949094179093559151600383015591516004909101555b600e548110156121af5787600d6000600e848154811061211357612113615b26565b60009182526020808320909101546001600160a01b031683528201929092526040018120600101805490919061214a908490615b52565b90915550506006546000908152600860205260408120600e80548b9391908590811061217857612178615b26565b60009182526020808320909101546001600160a01b03168352820192909252604001902055806121a781615b6a565b9150506120f1565b506006546001600160a01b038481166000908152600b602090815260408083208785168452825280832062ffffff8716845282528083208590558a8416808452600c835292819020859055518b81529288169391927f0621c8de33a230aec1aee0d4f7b6c81d97bd3ce0a2040ca33fbd668e521ecafe910160405180910390a450505050505050565b612240614296565b805161225f576040516332e7879360e01b815260040160405180910390fd5b600381511115612282576040516303451c2960e21b815260040160405180910390fd5b60005b600e54811015612406576000805b8351811015612308578381815181106122ae576122ae615b26565b60200260200101516001600160a01b0316600e84815481106122d2576122d2615b26565b6000918252602090912001546001600160a01b031614156122f65760019150612308565b8061230081615b6a565b915050612293565b50806123f3576000600d6000600e858154811061232757612327615b26565b60009182526020808320909101546001600160a01b039081168452838201949094526040928301909120825160e081018452815490941684526001810154918401919091526002810154918301919091526003810154606083015260048101546080830152600581015460a0830181905260069091015460c08301529091504210156123f157600e83815481106123c0576123c0615b26565b600091825260209091200154604051631901cdd360e31b81526001600160a01b039091166004820152602401611244565b505b50806123fe81615b6a565b915050612285565b50805161241a90600e9060208401906153ab565b50806040516124299190615da3565b604051908190038120907f68ba79316f2f1e5b9cbebbec19a0fbb2c29806dffa531995229a0bac2af9659590600090a250565b6000806000612469613eb4565b83516000908152600960205260409020600281015461249b5760405163079f151f60e11b815260040160405180910390fd5b6002810154600090815260076020908152604090912060018101549187015190916124d1916001600160a01b0390911690614cba565b600281015460408701516124ee916001600160a01b031690614cba565b60018101547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116911614801590612560575060028101547f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03908116911614155b801561256c5750600034115b1561257657600080fd5b6040805163219f5d1760e01b81528751600482015260208801516024820152908701516044820152606087015160648201526080870151608482015260a087015160a48201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063219f5d1790349060c40160606040518083038185885af1158015612610573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906126359190615de2565b60208901519297509095509350600090612650908690615be2565b905060008488604001516126649190615be2565b90508115612684576001830154612684906001600160a01b031683614d35565b80156126a25760028301546126a2906001600160a01b031682614d35565b60005b600e548110156126f7576126e485600e83815481106126c6576126c6615b26565b60009182526020822001548c516001600160a01b0390911691613f0c565b50806126ef81615b6a565b9150506126a5565b50612708848960000151600061447d565b505050506127166001600255565b9193909250565b6001600160a01b03821660009081526003602052604081205482106127925760405162461bcd60e51b815260206004820152602560248201527f456e756d657261626c653a206f776e657220696e646578206f7574206f6620626044820152646f756e647360d81b6064820152608401611244565b506001600160a01b03919091166000908152600460209081526040808320938352929052205490565b6127c3613eb4565b60008181526009602052604090206001810154600160301b90046001600160a01b03163314612805576040516330cd747160e01b815260040160405180910390fd5b80546001600160801b03161561282e576040516332e7879360e01b815260040160405180910390fd5b600082815260096020526040812081815560018101805479ffffffffffffffffffffffffffffffffffffffffffffffffffff191690556002810182905560030155612879338361426a565b6011546001600160a01b0316156128fc57601154600282015460405163622cd4e160e11b81523360048201526024810185905260448101919091526001600160a01b039091169063c459a9c290606401600060405180830381600087803b1580156128e357600080fd5b505af11580156128f7573d6000803e3d6000fd5b505050505b604051630852cd8d60e31b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c6890602401600060405180830381600087803b15801561295e57600080fd5b505af1158015612972573d6000803e3d6000fd5b50505060028201546040516000815284925033907ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb5679060200160405180910390a4506129be6001600255565b50565b6012546001600160a01b031633148015906129e757506000546001600160a01b03163314155b15612a0557604051634c7bb68760e11b815260040160405180910390fd5b4260005b82811015612b4157600060076000868685818110612a2957612a29615b26565b905060200201358152602001908152602001600020905060008160000160009054906101000a90046001600160a01b03166001600160a01b031663540d49186040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612abb9190615b95565b90506001600160a01b03811615612b2c576040516310a537f160e11b815263ffffffff851660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b158015612b1357600080fd5b505af1158015612b27573d6000803e3d6000fd5b505050505b50508080612b3990615b6a565b915050612a09565b50505050565b612b4f614296565b82801580612b5e575060065481115b15612b7c576040516387e8068360e01b815260040160405180910390fd5b600084815260076020908152604080832080548251630a81a92360e31b815292514295929492936001600160a01b039092169263540d491892600480820193918290030181865afa158015612bd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf99190615b95565b90506001600160a01b03811615612c6a576040516310a537f160e11b815263ffffffff841660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b158015612c5157600080fd5b505af1158015612c65573d6000803e3d6000fd5b505050505b8415612c7857612c78614370565b60005b600e54811015612ddb576000888152600860205260408120600e80548a93919085908110612cab57612cab615b26565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002054600d6000600e8581548110612d0157612d01615b26565b60009182526020808320909101546001600160a01b03168352820192909252604001902060010154612d339190615be2565b612d3d9190615b52565b600d6000600e8481548110612d5457612d54615b26565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120600101939093558a835260089091528120600e80548a93919085908110612da457612da4615b26565b60009182526020808320909101546001600160a01b0316835282019290925260400190205580612dd381615b6a565b915050612c7b565b50867fc0cfd54d2de2b55f1e6e108d3ec53ff0a1abe6055401d32c61e9433b747ef9f887604051612e0e91815260200190565b60405180910390a250505050505050565b6011546001600160a01b03163314612e795760405162461bcd60e51b815260206004820152601760248201527f4e6f74206661726d20626f6f737420636f6e74726163740000000000000000006044820152606401611244565b60008281526009602052604090206002810154612ea95760405163079f151f60e11b815260040160405180910390fd5b60005b600e54811015612efc57612ee982600e8381548110612ecd57612ecd615b26565b60009182526020822001546001600160a01b0316908790613f0c565b5080612ef481615b6a565b915050612eac565b50612f0881848461447d565b505050565b6001600160a01b0382166000908152600d6020526040812060010154819015612f83576001600160a01b0384166000818152600d60208181526040808420600181015489865260088452828620968652958352932054919052600690910154612f769190615bf9565b612f809190615c18565b91505b506001600160a01b039092166000908152600d602052604090206005015491929050565b60006001600160a01b0382166130255760405162461bcd60e51b815260206004820152602d60248201527f456e756d657261626c653a2061646472657373207a65726f206973206e6f742060448201527f612076616c6964206f776e6572000000000000000000000000000000000000006064820152608401611244565b506001600160a01b031660009081526003602052604090205490565b613049614296565b6130536000614e0c565b565b61305d614296565b6001600160a01b0381166130845760405163d92e233d60e01b815260040160405180910390fd5b60005b600e5481101561314057600019600e82815481106130a7576130a7615b26565b600091825260209091200154604051636eb1769f60e11b81526001600160a01b0385811660048301523060248301529091169063dd62ed3e90604401602060405180830381865afa158015613100573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131249190615d8a565b1461312e57600080fd5b8061313881615b6a565b915050613087565b50600f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f4a2963bfc20b87a0c055468a66e6638d57725e93fb4d65733fb2f25587ae8c4f906020016111e3565b60015433906001600160a01b031681146131fd5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401611244565b6129be81614e0c565b6001600160a01b0382166000908152600d6020526040812060010154819015612f83576001600160a01b038085166000818152600d602081815260408084206001810154968a168552600c835281852054855260088352818520958552948252909220549152600690910154612f769190615bf9565b600e818154811061328c57600080fd5b6000918252602090912001546001600160a01b0316905081565b6132ae614296565b620151808110806132c1575062278d0081115b156132df57604051634f08daf360e11b815260040160405180910390fd5b60138190556040518181527fb5521c8a03b484502769158d9dd83186bd0748f3ece2fbf358233994c2a20976906020016111e3565b60608167ffffffffffffffff81111561332f5761332f6154f3565b60405190808252806020026020018201604052801561336257816020015b606081526020019060019003908161334d5790505b50905060005b82811015613465576000803086868581811061338657613386615b26565b90506020028101906133989190615e19565b6040516133a6929190615e60565b600060405180830381855af49150503d80600081146133e1576040519150601f19603f3d011682016040523d82523d6000602084013e6133e6565b606091505b509150915081613432576044815110156133ff57600080fd5b600481019050808060200190518101906134199190615e70565b60405162461bcd60e51b81526004016112449190615f04565b8084848151811061344557613445615b26565b60200260200101819052505050808061345d90615b6a565b915050613368565b5092915050565b613474614296565b6001600160a01b03811661349b5760405163d92e233d60e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b0383169081179091556040519081527fc47d127c07bdd56c5ccba00463ce3bd3c1bca71b4670eea6e5d0c02e4aa156e2906020016111e3565b6060600e80548060200260200160405190810160405280929190818152602001828054801561354157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613523575b5050505050905090565b613553613eb4565b600081815260096020526040902060028101546135835760405163079f151f60e11b815260040160405180910390fd5b60005b600e548110156135d6576135c382600e83815481106135a7576135a7615b26565b60009182526020822001546001600160a01b0316908690613f0c565b50806135ce81615b6a565b915050613586565b506135e38183600061447d565b506129be6001600255565b6135f6614296565b6001600160a01b03811661361d5760405163d92e233d60e01b815260040160405180910390fd5b601080546001600160a01b0319166001600160a01b0383169081179091556040519081527f29e3e57b4a1e4513d009781598c7e4b8b2a68e4b71fe977e362d1b591016fade906020016111e3565b613673614296565b601180546001600160a01b0319166001600160a01b0383169081179091556040517ff32244aa081c72b930bb47bb702115e112d779ed353d6b1a70b28babc9822b7a90600090a250565b6136c5613eb4565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa15801561370c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137309190615d8a565b905060005b600e5481101561382557600e818154811061375257613752615b26565b6000918252602090912001546001600160a01b03868116911614156137d8576001600160a01b0385166000908152600d602052604090206002015482106137b8576001600160a01b0385166000908152600d6020526040902060020154909103906137d8565b6001600160a01b0385166000908152600d60205260408120600201929092555b838210156137f957604051632ca2f52b60e11b815260040160405180910390fd5b8115613813576138136001600160a01b0386168484614e25565b8061381d81615b6a565b915050613735565b5050612f086001600255565b613839613eb4565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156138a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138c49190615d8a565b9050828110156138e757604051632ca2f52b60e11b815260040160405180910390fd5b801561397157604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561394f57600080fd5b505af1158015613963573d6000803e3d6000fd5b505050506139718282614e55565b5061397c6001600255565b5050565b613988614296565b600180546001600160a01b0383166001600160a01b031990911681179091556139b96000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000818152600960209081526040808320815160e08101835281546001600160801b038082168352600160801b90910416938101939093526001810154600281810b9385019390935263010000008104830b6060850152600160301b90046001600160a01b031660808401529081015460a0830181905260039091015460c0830152156134655760a0818101516000908152600760209081526040808320815160c08101835281546001600160a01b039081168083526001840154821683870152600284015491821683860152600160a01b90910462ffffff16606083015260038301546080830152600492830154968201969096528251630a81a92360e31b8152925190959363540d49189380840193919291908290030181865afa158015613b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b439190615b95565b90506001600160a01b03811615613c3357604083810151606085015191516301e72ef560e71b81526001600160a01b038981166004830152600292830b60248301529290910b604482015260009183169063f3977a8090606401602060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde9190615d8a565b6000878152600a602090815260408083206001600160a01b038c16845282529091205490860151919250820390600160801b90613c24906001600160801b031683615bf9565b613c2e9190615c18565b955050505b6000858152600a602090815260408083206001600160a01b038a168452909152902060010154613c639085615b52565b9695505050505050565b6000613c77613eb4565b60008381526009602052604090206001810154600160301b90046001600160a01b03163314613cb9576040516330cd747160e01b815260040160405180910390fd5b80546001600160801b0316158015613cf457506000848152600a602090815260408083206001600160a01b0389168452909152902060010154155b15613d1257604051636180f03f60e11b815260040160405180910390fd5b613d1e81868686613f0c565b915050613d2b6001600255565b9392505050565b600080613d3d613eb4565b825160009081526009602052604090206001810154600160301b90046001600160a01b03163314613d81576040516330cd747160e01b815260040160405180910390fd5b60208401516001600160a01b0316613d9a573060208501525b6040805163fc6f786560e01b81528551600482015260208601516001600160a01b039081166024830152918601516001600160801b03908116604483015260608701511660648201527f00000000000000000000000000000000000000000000000000000000000000009091169063fc6f78659060840160408051808303816000875af1158015613e2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e539190615c3a565b90935091506115e790506001600255565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600280541415613f065760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611244565b60028055565b6002848101546000908152600760209081526040808320815160c08101835281546001600160a01b0390811680835260018401548216838701529683015490811682850152600160a01b900462ffffff1660608201526003820154608082015260049182015460a08201528251630a81a92360e31b81529251949590948694919363540d4918938181019392918290030181865afa158015613fb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd69190615b95565b90506001600160a01b03811615801590613ffa5750601154600160a01b900460ff16155b15614165576040516310a537f160e11b815263ffffffff421660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b15801561404657600080fd5b505af115801561405a573d6000803e3d6000fd5b5050505060018701546040516301e72ef560e71b81526001600160a01b038881166004830152600283810b6024840152630100000090930490920b604482015260009183169063f3977a8090606401602060405180830381865afa1580156140c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ea9190615d8a565b6000878152600a602090815260408083206001600160a01b038c1684529091529020548954919250820390600160801b90614131908290046001600160801b031683615bf9565b61413b9190615c18565b6000888152600a602090815260408083206001600160a01b038d1684529091529020929092555092505b6000858152600a602090815260408083206001600160a01b038a1684529091529020600101546141959084615b52565b92508215614260576001600160a01b03841615614237576000858152600a602090815260408083206001600160a01b038a1684529091528120600101556141dd868585614eb5565b6002870154604080516001600160a01b0387811682528916602082015290810185905286919033907f282b9c6f6d6a6b0d9b4175a3af0be477af589c6cb2d91400d87972ef449876d79060600160405180910390a4614260565b6000858152600a602090815260408083206001600160a01b038a16845290915290206001018390555b5050949350505050565b6142748282614fb3565b506001600160a01b031660009081526003602052604090208054600019019055565b6000546001600160a01b031633146130535760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611244565b6040516001600160a01b0380851660248301528316604482015260648101829052612b419085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909316929092179091526150cd565b4260015b600654811161397c57600081815260076020908152604080832080548251630a81a92360e31b815292519194936001600160a01b039091169263540d491892600480830193928290030181865afa1580156143d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143f79190615b95565b90506001600160a01b03811615614468576040516310a537f160e11b815263ffffffff851660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b15801561444f57600080fd5b505af1158015614463573d6000803e3d6000fd5b505050505b5050808061447590615b6a565b915050614374565b60008060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166399fbab88866040518263ffffffff1660e01b81526004016144d091815260200190565b61018060405180830381865afa1580156144ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145129190615c8e565b5050505060028e015460009081526007602052604090208e54939b50919950975095506001600160801b03808816911614935061459e9250505057865460038201546001600160801b038085169261456c92911690615be2565b6145769190615b52565b600382015586546fffffffffffffffffffffffffffffffff19166001600160801b0383161787555b60115464e8d4a51000906001600160a01b0316158015906145bd575085155b1561463857601154604051632273df8360e11b8152600481018990526001600160a01b03909116906344e7bf06906024016020604051808303816000875af115801561460d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146319190615d8a565b9050614641565b85156146415750845b64e8d4a5100081101561465a575064e8d4a51000614671565b6501d1a94a200081111561467157506501d1a94a20005b6003880181905560006146a564e8d4a51000614696846001600160801b038816615bf9565b6146a09190615c18565b6151b5565b89549091506000906146c790600160801b90046001600160801b031683615f17565b905080600f0b60001461499057895460048501546001600160801b03808516926146fc92600160801b90910490911690615be2565b6147069190615b52565b6004808601919091558a546001600160801b03808516600160801b029116178b55845460408051630a81a92360e31b815290516000936001600160a01b039093169263540d4918928082019260209290918290030181865afa158015614770573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147949190615b95565b90506001600160a01b0381166147bd5760405163ef3d9b2160e01b815260040160405180910390fd5b604051638910faf160e01b8152600289810b600483015288900b6024820152600f83900b60448201526001600160a01b03821690638910faf190606401600060405180830381600087803b15801561481457600080fd5b505af1158015614828573d6000803e3d6000fd5b5050505060005b600e5481101561493d57816001600160a01b031663f3977a80600e838154811061485b5761485b615b26565b60009182526020909120015460405160e083901b6001600160e01b03191681526001600160a01b03909116600482015260028c810b60248301528b900b6044820152606401602060405180830381865afa1580156148bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148e19190615d8a565b60008c8152600a60205260408120600e80549192918590811061490657614906615b26565b60009182526020808320909101546001600160a01b031683528201929092526040019020558061493581615b6a565b91505061482f565b5060028b81015460408051600f86900b81528b840b6020820152928a900b83820152518c9233917fee8f6362d59839b4b3c990d7e085a63a0fe2c58f4eff4a9a2b6de93a4c645ae39181900360600190a4505b50505050505050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156149e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a079190615d8a565b905060005b600e54811015612b4157600e8181548110614a2957614a29615b26565b6000918252602090912001546001600160a01b0385811691161415614aaf576001600160a01b0384166000908152600d60205260409020600201548210614a8f576001600160a01b0384166000908152600d602052604090206002015490910390614aaf565b6001600160a01b0384166000908152600d60205260408120600201929092555b8115614b8c577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161415614b7857604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015614b5157600080fd5b505af1158015614b65573d6000803e3d6000fd5b50505050614b738383614e55565b614b8c565b614b8c6001600160a01b0385168484614e25565b80614b9681615b6a565b915050614a0c565b801580614c185750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c169190615d8a565b155b614c8a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401611244565b6040516001600160a01b038316602482015260448101829052612f0890849063095ea7b360e01b90606401614324565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148015614cfb5750600034115b15614d205780341461397c57604051634b508fef60e01b815260040160405180910390fd5b61397c6001600160a01b0383163330846142f0565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316148015614d765750600034115b15614df8577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631f9709826040518163ffffffff1660e01b8152600401600060405180830381600087803b158015614dd657600080fd5b505af1158015614dea573d6000803e3d6000fd5b5050505061397c3347614e55565b61397c6001600160a01b0383163383614e25565b600180546001600160a01b03191690556129be81613e64565b6040516001600160a01b038316602482015260448101829052612f0890849063a9059cbb60e01b90606401614324565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614ea2576040519150601f19603f3d011682016040523d82523d6000602084013e614ea7565b606091505b5050905080612f0857600080fd5b8015612f08576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015614f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f269190615d8a565b905081811015614f34578091505b6001600160a01b0384166000908152600d60205260409020600201548211614f7d576001600160a01b0384166000908152600d6020526040902060020180548390039055614f9f565b6001600160a01b0384166000908152600d602052604090208282036002909101555b612b416001600160a01b0385168484614e25565b6001600160a01b038216600090815260036020526040812054614fd890600190615be2565b6000838152600560209081526040808320546001600160a01b038816845260048352818420818552909252909120549192509083146150595760405162461bcd60e51b815260206004820152600f60248201527f496e76616c696420746f6b656e496400000000000000000000000000000000006044820152606401611244565b81811461509a576001600160a01b03841660009081526004602090815260408083208584528252808320548484528184208190558352600590915290208190555b5060009182526005602090815260408084208490556001600160a01b039094168352600481528383209183525290812055565b6000615122826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661521e9092919063ffffffff16565b90508051600014806151435750808060200190518101906151439190615f79565b612f085760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611244565b6000600160801b821061521a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401611244565b5090565b606061522d8484600085615235565b949350505050565b6060824710156152965760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611244565b600080866001600160a01b031685876040516152b29190615f96565b60006040518083038185875af1925050503d80600081146152ef576040519150601f19603f3d011682016040523d82523d6000602084013e6152f4565b606091505b509150915061530587838387615310565b979650505050505050565b6060831561537c578251615375576001600160a01b0385163b6153755760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611244565b508161522d565b61522d83838151156153915781518083602001fd5b8060405162461bcd60e51b81526004016112449190615f04565b828054828255906000526020600020908101928215615400579160200282015b8281111561540057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906153cb565b5061521a9291505b8082111561521a5760008155600101615408565b6001600160a01b03811681146129be57600080fd5b6000806040838503121561544457600080fd5b8235915060208301356154568161541c565b809150509250929050565b80151581146129be57600080fd5b60006020828403121561548157600080fd5b8135613d2b81615461565b600080600080608085870312156154a257600080fd5b84356154ad8161541c565b9350602085013592506040850135915060608501356154cb81615461565b939692955090935050565b6000602082840312156154e857600080fd5b8135613d2b8161541c565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715615532576155326154f3565b604052919050565b6001600160801b03811681146129be57600080fd5b600060a0828403121561556157600080fd5b60405160a0810181811067ffffffffffffffff82111715615584576155846154f3565b6040528235815260208301356155998161553a565b806020830152506040830135604082015260608301356060820152608083013560808201528091505092915050565b6000608082840312156155da57600080fd5b6040516080810181811067ffffffffffffffff821117156155fd576155fd6154f3565b6040528235815290508060208301356156158161541c565b602082015260408301356156288161553a565b6040820152606083013561563b8161553a565b6060919091015292915050565b60008060a0838503121561565b57600080fd5b61566584846155c8565b915060808301356154568161541c565b60008060008060006080868803121561568d57600080fd5b85356156988161541c565b945060208601356156a88161541c565b935060408601359250606086013567ffffffffffffffff808211156156cc57600080fd5b818801915088601f8301126156e057600080fd5b8135818111156156ef57600080fd5b89602082850101111561570157600080fd5b9699959850939650602001949392505050565b60006020828403121561572657600080fd5b5035919050565b60008060006060848603121561574257600080fd5b8335925060208401356157548161541c565b9150604084013561576481615461565b809150509250925092565b6000602080838503121561578257600080fd5b823567ffffffffffffffff8082111561579a57600080fd5b818501915085601f8301126157ae57600080fd5b8135818111156157c0576157c06154f3565b8060051b91506157d1848301615509565b81815291830184019184810190888411156157eb57600080fd5b938501935b8385101561581557843592506158058361541c565b82825293850193908501906157f0565b98975050505050505050565b600060c0828403121561583357600080fd5b60405160c0810181811067ffffffffffffffff82111715615856576158566154f3565b8060405250823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b600080604083850312156158ae57600080fd5b82356158b98161541c565b946020939093013593505050565b60008083601f8401126158d957600080fd5b50813567ffffffffffffffff8111156158f157600080fd5b6020830191508360208260051b850101111561178957600080fd5b6000806020838503121561591f57600080fd5b823567ffffffffffffffff81111561593657600080fd5b615942858286016158c7565b90969095509350505050565b60008060006060848603121561596357600080fd5b8335925060208401359150604084013561576481615461565b6000806040838503121561598f57600080fd5b50508035926020909101359150565b600080604083850312156159b157600080fd5b82356159bc8161541c565b915060208301356154568161541c565b60005b838110156159e75781810151838201526020016159cf565b83811115612b415750506000910152565b60008151808452615a108160208601602086016159cc565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015615a7957603f19888603018452615a678583516159f8565b94509285019290850190600101615a4b565b5092979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015615ac75783516001600160a01b031683529284019291840191600101615aa2565b50909695505050505050565b600080600060608486031215615ae857600080fd5b8335615af38161541c565b92506020840135915060408401356157648161541c565b600060808284031215615b1c57600080fd5b613d2b83836155c8565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115615b6557615b65615b3c565b500190565b6000600019821415615b7e57615b7e615b3c565b5060010190565b8051615b908161541c565b919050565b600060208284031215615ba757600080fd5b8151613d2b8161541c565b600081600f0b6f7fffffffffffffffffffffffffffffff19811415615bd957615bd9615b3c565b60000392915050565b600082821015615bf457615bf4615b3c565b500390565b6000816000190483118215151615615c1357615c13615b3c565b500290565b600082615c3557634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215615c4d57600080fd5b505080516020909101519092909150565b805162ffffff81168114615b9057600080fd5b8051600281900b8114615b9057600080fd5b8051615b908161553a565b6000806000806000806000806000806000806101808d8f031215615cb157600080fd5b8c516bffffffffffffffffffffffff81168114615ccd57600080fd5b9b50615cdb60208e01615b85565b9a50615ce960408e01615b85565b9950615cf760608e01615b85565b9850615d0560808e01615c5e565b9750615d1360a08e01615c71565b9650615d2160c08e01615c71565b9550615d2f60e08e01615c83565b94506101008d015193506101208d01519250615d4e6101408e01615c83565b9150615d5d6101608e01615c83565b90509295989b509295989b509295989b565b600060208284031215615d8157600080fd5b613d2b82615c5e565b600060208284031215615d9c57600080fd5b5051919050565b815160009082906020808601845b83811015615dd65781516001600160a01b031685529382019390820190600101615db1565b50929695505050505050565b600080600060608486031215615df757600080fd5b8351615e028161553a565b602085015160409095015190969495509392505050565b6000808335601e19843603018112615e3057600080fd5b83018035915067ffffffffffffffff821115615e4b57600080fd5b60200191503681900382131561178957600080fd5b8183823760009101908152919050565b600060208284031215615e8257600080fd5b815167ffffffffffffffff80821115615e9a57600080fd5b818401915084601f830112615eae57600080fd5b815181811115615ec057615ec06154f3565b615ed3601f8201601f1916602001615509565b9150808252856020828501011115615eea57600080fd5b615efb8160208401602086016159cc565b50949350505050565b602081526000613d2b60208301846159f8565b600081600f0b83600f0b60008112816f7fffffffffffffffffffffffffffffff1901831281151615615f4b57615f4b615b3c565b816f7fffffffffffffffffffffffffffffff018313811615615f6f57615f6f615b3c565b5090039392505050565b600060208284031215615f8b57600080fd5b8151613d2b81615461565b60008251615fa88184602087016159cc565b919091019291505056fea2646970667358221220dccd53a6d7511cc0a8716e3a35993a353d895644768beec42ee9dbb63a20154c64736f6c634300080a003300000000000000000000000000000000000000000000000000000000000000600000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000001516000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061036e5760003560e01c806379ba5097116101c6578063caa6fea4116100f7578063eff7a11311610095578063f54ac2461161006f578063f54ac24614610c75578063f7260d3e14610c95578063fbc911d014610cb5578063fc6f786514610cd557600080fd5b8063eff7a11314610c15578063f2fde38b14610c35578063f430cf0d14610c5557600080fd5b8063cf242849116100d1578063cf24284914610b97578063cfb8ccfb14610bb7578063df2ab5bb14610bd7578063e30c397814610bf757600080fd5b8063caa6fea414610b46578063cc6db2da14610a49578063ced0911214610b7757600080fd5b8063ac9650d811610164578063b44a27221161013e578063b44a272214610ab9578063b4ce128014610aed578063b6a6d17714610b0d578063c4f59f9b14610b2457600080fd5b8063ac9650d814610a62578063b1724b4614610a82578063b3ab15fb14610a9957600080fd5b80637c2d6e01116101a05780637c2d6e01146109d75780638da5cb5b146109f75780639ba879cf14610a15578063aaf5eb6814610a4957600080fd5b806379ba5097146109825780637bb21b46146109975780637bb7bed1146109b757600080fd5b8063233a48a2116102a05780636558954f1161023e57806369b021281161021857806369b021281461091357806370a082311461092d578063715018a61461094d578063718da7ee1461096257600080fd5b80636558954f146108bd57806369746a1d146108d3578063699233c3146108f357600080fd5b806342966c681161027a57806342966c681461084857806344780994146108685780635d0cde971461088857806364482f791461089d57600080fd5b8063233a48a2146106c15780632f745c59146107625780633b1acf741461078257600080fd5b80630d55f9131161030d5780631526fe27116102e75780631526fe27146105a15780631eaaa04514610649578063201e81a814610669578063219f5d171461068957600080fd5b80630d55f91314610510578063127effb214610530578063150b7a021461056857600080fd5b8063070f3c0711610349578063070f3c071461048d5780630743384d146104ad578063081e3eda146104da5780630c49ccbe146104f057600080fd5b8062f714ce146103e65780630327ae47146104195780630501d5561461046d57600080fd5b366103e157336001600160a01b037f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b16148015906103d55750336001600160a01b037f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a1614155b156103df57600080fd5b005b600080fd5b3480156103f257600080fd5b50610406610401366004615431565b610cf5565b6040519081526020015b60405180910390f35b34801561042557600080fd5b50610458610434366004615431565b600a6020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610410565b34801561047957600080fd5b506103df61048836600461546f565b611179565b34801561049957600080fd5b506103df6104a836600461548c565b6111ee565b3480156104b957600080fd5b506104066104c83660046154d6565b600c6020526000908152604090205481565b3480156104e657600080fd5b5061040660065481565b3480156104fc57600080fd5b5061045861050b36600461554f565b611467565b34801561051c57600080fd5b5061045861052b366004615648565b6115ec565b34801561053c57600080fd5b50601254610550906001600160a01b031681565b6040516001600160a01b039091168152602001610410565b34801561057457600080fd5b50610588610583366004615675565b611790565b6040516001600160e01b03199091168152602001610410565b3480156105ad57600080fd5b506106066105bc366004615714565b600760205260009081526040902080546001820154600283015460038401546004909401546001600160a01b039384169492841693821692600160a01b90920462ffffff16919086565b604080516001600160a01b0397881681529587166020870152939095169284019290925262ffffff166060830152608082015260a081019190915260c001610410565b34801561065557600080fd5b506103df61066436600461572d565b611c39565b34801561067557600080fd5b506103df61068436600461576f565b612238565b61069c610697366004615821565b61245c565b604080516001600160801b039094168452602084019290925290820152606001610410565b3480156106cd57600080fd5b506107236106dc3660046154d6565b600d6020526000908152604090208054600182015460028301546003840154600485015460058601546006909601546001600160a01b039095169593949293919290919087565b604080516001600160a01b0390981688526020880196909652948601939093526060850191909152608084015260a083015260c082015260e001610410565b34801561076e57600080fd5b5061040661077d36600461589b565b61271d565b34801561078e57600080fd5b506107f761079d366004615714565b6009602052600090815260409020805460018201546002808401546003909401546001600160801b0380851695600160801b909504169383830b936301000000810490930b92600160301b90046001600160a01b03169187565b604080516001600160801b039889168152979096166020880152600294850b958701959095529190920b60608501526001600160a01b03909116608084015260a083015260c082015260e001610410565b34801561085457600080fd5b506103df610863366004615714565b6127bb565b34801561087457600080fd5b506103df61088336600461590c565b6129c1565b34801561089457600080fd5b50610406600381565b3480156108a957600080fd5b506103df6108b836600461594e565b612b47565b3480156108c957600080fd5b5061040660135481565b3480156108df57600080fd5b506103df6108ee36600461597c565b612e1f565b3480156108ff57600080fd5b5061045861090e36600461589b565b612f0d565b34801561091f57600080fd5b506104066501d1a94a200081565b34801561093957600080fd5b506104066109483660046154d6565b612fa7565b34801561095957600080fd5b506103df613041565b34801561096e57600080fd5b506103df61097d3660046154d6565b613055565b34801561098e57600080fd5b506103df61318f565b3480156109a357600080fd5b506104586109b236600461599e565b613206565b3480156109c357600080fd5b506105506109d2366004615714565b61327c565b3480156109e357600080fd5b506103df6109f2366004615714565b6132a6565b348015610a0357600080fd5b506000546001600160a01b0316610550565b348015610a2157600080fd5b506105507f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a81565b348015610a5557600080fd5b5061040664e8d4a5100081565b610a75610a7036600461590c565b613314565b6040516104109190615a24565b348015610a8e57600080fd5b5061040662278d0081565b348015610aa557600080fd5b506103df610ab43660046154d6565b61346c565b348015610ac557600080fd5b506105507f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b81565b348015610af957600080fd5b50601054610550906001600160a01b031681565b348015610b1957600080fd5b506104066201518081565b348015610b3057600080fd5b50610b396134e9565b6040516104109190615a86565b348015610b5257600080fd5b50601154610b6790600160a01b900460ff1681565b6040519015158152602001610410565b348015610b8357600080fd5b506103df610b92366004615714565b61354b565b348015610ba357600080fd5b506103df610bb23660046154d6565b6135ee565b348015610bc357600080fd5b506103df610bd23660046154d6565b61366b565b348015610be357600080fd5b506103df610bf2366004615ad3565b6136bd565b348015610c0357600080fd5b506001546001600160a01b0316610550565b348015610c2157600080fd5b506103df610c30366004615431565b613831565b348015610c4157600080fd5b506103df610c503660046154d6565b613980565b348015610c6157600080fd5b50610406610c7036600461589b565b6139f1565b348015610c8157600080fd5b50610406610c90366004615ad3565b613c6d565b348015610ca157600080fd5b50600f54610550906001600160a01b031681565b348015610cc157600080fd5b50601154610550906001600160a01b031681565b348015610ce157600080fd5b50610458610cf0366004615b0a565b613d32565b6000610cff613eb4565b6001600160a01b038216301480610d1d57506001600160a01b038216155b15610d3b57604051631964c57360e11b815260040160405180910390fd5b60008381526009602052604090206001810154600160301b90046001600160a01b03163314610d7d576040516330cd747160e01b815260040160405180910390fd5b60005b600e54811015610ddb57610dbd82600e8381548110610da157610da1615b26565b6000918252602090912001546001600160a01b03168787613f0c565b610dc79084615b52565b925080610dd381615b6a565b915050610d80565b506002810154600081815260076020908152604080832080548251630a81a92360e31b815292519194936001600160a01b039091169263540d491892600480830193928290030181865afa158015610e37573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5b9190615b95565b90506001600160a01b03811615801590610e7f5750601154600160a01b900460ff16155b15610f7f578354600090610ea290600160801b90046001600160801b0316615bb2565b6001860154604051638910faf160e01b8152600282810b6004830152630100000090920490910b6024820152600f82900b60448201529091506001600160a01b03831690638910faf190606401600060405180830381600087803b158015610f0957600080fd5b505af1158015610f1d573d6000803e3d6000fd5b50505050600185015460408051600f84900b8152600283810b6020830152630100000090930490920b908201528890859033907fee8f6362d59839b4b3c990d7e085a63a0fe2c58f4eff4a9a2b6de93a4c645ae39060600160405180910390a4505b83546003830180546001600160801b0390921691600090610fa1908490615be2565b90915550508354600483018054600160801b9092046001600160801b031691600090610fce908490615be2565b9091555050600087815260096020526040812081815560018101805479ffffffffffffffffffffffffffffffffffffffffffffffffffff19169055600281018290556003015561101e338861426a565b6011546001600160a01b03161561109b5760115460405163622cd4e160e11b815233600482015260248101899052604481018590526001600160a01b039091169063c459a9c290606401600060405180830381600087803b15801561108257600080fd5b505af1158015611096573d6000803e3d6000fd5b505050505b604051632142170760e11b81523060048201526001600160a01b038781166024830152604482018990527f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b16906342842e0e90606401600060405180830381600087803b15801561110b57600080fd5b505af115801561111f573d6000803e3d6000fd5b50506040516001600160a01b038916815289925085915033907ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb5679060200160405180910390a4505050506111736001600255565b92915050565b611181614296565b6011805474ff00000000000000000000000000000000000000001916600160a01b8315158102919091179182905560405160ff9190920416151581527fc749456be5379ac4cfc1f856208b32ddcf01b9db3ce6c37784ad91a8390ae9a8906020015b60405180910390a150565b600f546001600160a01b0316331461124d5760405162461bcd60e51b815260206004820152600c60248201527f4e6f74207265636569766572000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600f54611268906001600160a01b03868116911630866142f0565b6001600160a01b0384166000908152600d60205260409020600201805484019055801561129757611297614370565b6013546201518083108015906112b0575062278d008311155b156112b85750815b4260006112c58383615b52565b6001600160a01b0388166000908152600d60205260408120600501549192509087908410156113af576001600160a01b0389166000908152600d60205260408120600681015460059091015464e8d4a510009190611324908890615be2565b61132e9190615bf9565b6113389190615c18565b6001600160a01b038b166000818152600d6020908152604091829020600381015460059091015483519081529182018a9052918101849052929350917f220da7a534a80a110f7ff72f9922efb97f37355d49f903e0aaac1d19397458d19060600160405180910390a36113ab8183615b52565b9150505b846113bf64e8d4a5100083615bf9565b6113c99190615c18565b6001600160a01b038a166000818152600d6020526040902060038101805460019081019182905588810160048401556005830188905560069092018490559294507fadceb780601967fcb680db81d7a4540165bf0a39608785518a833a47683968cd90611437908890615b52565b604080519182526020820188905281018690526060810185905260800160405180910390a3505050505050505050565b600080611472613eb4565b825160009081526009602052604090206001810154600160301b90046001600160a01b031633146114b6576040516330cd747160e01b815260040160405180910390fd5b60408051630624e65f60e11b81528551600482015260208601516001600160801b0316602482015290850151604482015260608501516064820152608085015160848201527f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b6001600160a01b031690630c49ccbe9060a40160408051808303816000875af115801561154d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115719190615c3a565b909350915060005b600e548110156115cb576115b882600e838154811061159a5761159a615b26565b600091825260208220015488516001600160a01b0390911691613f0c565b50806115c381615b6a565b915050611579565b506115dc818560000151600061447d565b506115e76001600255565b915091565b6000806115f7613eb4565b835160009081526009602052604090206001810154600160301b90046001600160a01b0316331461163b576040516330cd747160e01b815260040160405180910390fd5b60208501516001600160a01b0316611654573060208601525b6040805163fc6f786560e01b81528651600482015260208701516001600160a01b039081166024830152918701516001600160801b03908116604483015260608801511660648201527f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b9091169063fc6f78659060840160408051808303816000875af11580156116e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061170d9190615c3a565b602087015191945092506001600160a01b031630141561177e57600281015460009081526007602052604090206001600160a01b03851661174c573394505b6001810154611764906001600160a01b03168661499c565b600281015461177c906001600160a01b03168661499c565b505b506117896001600255565b9250929050565b600061179a613eb4565b336001600160a01b037f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b16146117e3576040516314a5156160e21b815260040160405180910390fd5b6040805160c081018252600080825260208201819052818301819052606082018190526080820181905260a0820152905163133f757160e31b8152600481018690526001600160a01b037f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b16906399fbab889060240161018060405180830381865afa158015611877573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189b9190615c8e565b505050506001600160801b031660a08901819052600291820b60808a015291900b606088015262ffffff9190911660408701526001600160a01b0391821660208701529116845215159150611905905057604051636180f03f60e11b815260040160405180910390fd5b80516001600160a01b039081166000908152600b602090815260408083208286015190941683529281528282208385015162ffffff168352905220548061195f5760405163079f151f60e11b815260040160405180910390fd5b6000818152600760209081526040808320815160c08101835281546001600160a01b039081168083526001840154821683870152600284015491821683860152600160a01b90910462ffffff1660608301526003830154608083015260049283015460a08301528351630a81a92360e31b81529351919594909363540d49189381810193918290030181865afa1580156119fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a219190615b95565b90506001600160a01b038116611a4a5760405163ef3d9b2160e01b815260040160405180910390fd5b6000600960008a8152602001908152602001600020905084606001518160010160006101000a81548162ffffff021916908360020b62ffffff16021790555084608001518160010160036101000a81548162ffffff021916908360020b62ffffff160217905550898160010160066101000a8154816001600160a01b0302191690836001600160a01b03160217905550838160020181905550816001600160a01b031663214a6fe2426040518263ffffffff1660e01b8152600401611b1b919063ffffffff91909116815260200190565b600060405180830381600087803b158015611b3557600080fd5b505af1158015611b49573d6000803e3d6000fd5b50505050611b59818a600061447d565b611bac8a8a6001600160a01b039190911660008181526003602081815260408084208054600484528286208187528452828620889055968552600583529084209590955592909152905280546001019055565b60a08501516060808701516080880151604080516001600160801b039095168552600292830b6020860152910b908301528a9186916001600160a01b038e16917fb19157bff94fdd40c58c7d4a5d52e8eb8c2d570ca17b322b49a2bbbeedc82fbf910160405180910390a450630a85bd0160e11b945050505050611c306001600255565b95945050505050565b611c41614296565b8015611c4f57611c4f614370565b601054604051634c96a38960e01b81526001600160a01b0384811660048301526000921690634c96a389906024016020604051808303816000875af1158015611c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc09190615b95565b90506000836001600160a01b0316630dfe16816040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d269190615b95565b90506000846001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d8c9190615b95565b90506000856001600160a01b031663ddca3f436040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dce573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df29190615d6f565b6001600160a01b038085166000908152600b60209081526040808320938716835292815282822062ffffff851683529052205490915015611e7e576001600160a01b038381166000908152600b60209081526040808320938616835292815282822062ffffff851683529052819020549051637d38f65f60e01b81526004810191909152602401611244565b604051636eb1769f60e11b81523060048201526001600160a01b037f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b8116602483015284169063dd62ed3e90604401602060405180830381865afa158015611eea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0e9190615d8a565b611f4857611f486001600160a01b0384167f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b600019614b9e565b604051636eb1769f60e11b81523060048201526001600160a01b037f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b8116602483015283169063dd62ed3e90604401602060405180830381865afa158015611fb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd89190615d8a565b612012576120126001600160a01b0383167f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b600019614b9e565b600680546001908101918290556040805160c0810182526001600160a01b03808b168252878116602080840191825288831684860190815262ffffff808a166060870190815260006080880181815260a089018281529b82526007909552978820965187549087166001600160a01b0319918216178855945198870180549987169990951698909817909355516002850180549751909316600160a01b027fffffffffffffffffff0000000000000000000000000000000000000000000000909716931692909217949094179093559151600383015591516004909101555b600e548110156121af5787600d6000600e848154811061211357612113615b26565b60009182526020808320909101546001600160a01b031683528201929092526040018120600101805490919061214a908490615b52565b90915550506006546000908152600860205260408120600e80548b9391908590811061217857612178615b26565b60009182526020808320909101546001600160a01b03168352820192909252604001902055806121a781615b6a565b9150506120f1565b506006546001600160a01b038481166000908152600b602090815260408083208785168452825280832062ffffff8716845282528083208590558a8416808452600c835292819020859055518b81529288169391927f0621c8de33a230aec1aee0d4f7b6c81d97bd3ce0a2040ca33fbd668e521ecafe910160405180910390a450505050505050565b612240614296565b805161225f576040516332e7879360e01b815260040160405180910390fd5b600381511115612282576040516303451c2960e21b815260040160405180910390fd5b60005b600e54811015612406576000805b8351811015612308578381815181106122ae576122ae615b26565b60200260200101516001600160a01b0316600e84815481106122d2576122d2615b26565b6000918252602090912001546001600160a01b031614156122f65760019150612308565b8061230081615b6a565b915050612293565b50806123f3576000600d6000600e858154811061232757612327615b26565b60009182526020808320909101546001600160a01b039081168452838201949094526040928301909120825160e081018452815490941684526001810154918401919091526002810154918301919091526003810154606083015260048101546080830152600581015460a0830181905260069091015460c08301529091504210156123f157600e83815481106123c0576123c0615b26565b600091825260209091200154604051631901cdd360e31b81526001600160a01b039091166004820152602401611244565b505b50806123fe81615b6a565b915050612285565b50805161241a90600e9060208401906153ab565b50806040516124299190615da3565b604051908190038120907f68ba79316f2f1e5b9cbebbec19a0fbb2c29806dffa531995229a0bac2af9659590600090a250565b6000806000612469613eb4565b83516000908152600960205260409020600281015461249b5760405163079f151f60e11b815260040160405180910390fd5b6002810154600090815260076020908152604090912060018101549187015190916124d1916001600160a01b0390911690614cba565b600281015460408701516124ee916001600160a01b031690614cba565b60018101547f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b03908116911614801590612560575060028101547f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b03908116911614155b801561256c5750600034115b1561257657600080fd5b6040805163219f5d1760e01b81528751600482015260208801516024820152908701516044820152606087015160648201526080870151608482015260a087015160a48201527f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b6001600160a01b03169063219f5d1790349060c40160606040518083038185885af1158015612610573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906126359190615de2565b60208901519297509095509350600090612650908690615be2565b905060008488604001516126649190615be2565b90508115612684576001830154612684906001600160a01b031683614d35565b80156126a25760028301546126a2906001600160a01b031682614d35565b60005b600e548110156126f7576126e485600e83815481106126c6576126c6615b26565b60009182526020822001548c516001600160a01b0390911691613f0c565b50806126ef81615b6a565b9150506126a5565b50612708848960000151600061447d565b505050506127166001600255565b9193909250565b6001600160a01b03821660009081526003602052604081205482106127925760405162461bcd60e51b815260206004820152602560248201527f456e756d657261626c653a206f776e657220696e646578206f7574206f6620626044820152646f756e647360d81b6064820152608401611244565b506001600160a01b03919091166000908152600460209081526040808320938352929052205490565b6127c3613eb4565b60008181526009602052604090206001810154600160301b90046001600160a01b03163314612805576040516330cd747160e01b815260040160405180910390fd5b80546001600160801b03161561282e576040516332e7879360e01b815260040160405180910390fd5b600082815260096020526040812081815560018101805479ffffffffffffffffffffffffffffffffffffffffffffffffffff191690556002810182905560030155612879338361426a565b6011546001600160a01b0316156128fc57601154600282015460405163622cd4e160e11b81523360048201526024810185905260448101919091526001600160a01b039091169063c459a9c290606401600060405180830381600087803b1580156128e357600080fd5b505af11580156128f7573d6000803e3d6000fd5b505050505b604051630852cd8d60e31b8152600481018390527f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b6001600160a01b0316906342966c6890602401600060405180830381600087803b15801561295e57600080fd5b505af1158015612972573d6000803e3d6000fd5b50505060028201546040516000815284925033907ff341246adaac6f497bc2a656f546ab9e182111d630394f0c57c710a59a2cb5679060200160405180910390a4506129be6001600255565b50565b6012546001600160a01b031633148015906129e757506000546001600160a01b03163314155b15612a0557604051634c7bb68760e11b815260040160405180910390fd5b4260005b82811015612b4157600060076000868685818110612a2957612a29615b26565b905060200201358152602001908152602001600020905060008160000160009054906101000a90046001600160a01b03166001600160a01b031663540d49186040518163ffffffff1660e01b8152600401602060405180830381865afa158015612a97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612abb9190615b95565b90506001600160a01b03811615612b2c576040516310a537f160e11b815263ffffffff851660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b158015612b1357600080fd5b505af1158015612b27573d6000803e3d6000fd5b505050505b50508080612b3990615b6a565b915050612a09565b50505050565b612b4f614296565b82801580612b5e575060065481115b15612b7c576040516387e8068360e01b815260040160405180910390fd5b600084815260076020908152604080832080548251630a81a92360e31b815292514295929492936001600160a01b039092169263540d491892600480820193918290030181865afa158015612bd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bf99190615b95565b90506001600160a01b03811615612c6a576040516310a537f160e11b815263ffffffff841660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b158015612c5157600080fd5b505af1158015612c65573d6000803e3d6000fd5b505050505b8415612c7857612c78614370565b60005b600e54811015612ddb576000888152600860205260408120600e80548a93919085908110612cab57612cab615b26565b9060005260206000200160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002054600d6000600e8581548110612d0157612d01615b26565b60009182526020808320909101546001600160a01b03168352820192909252604001902060010154612d339190615be2565b612d3d9190615b52565b600d6000600e8481548110612d5457612d54615b26565b60009182526020808320909101546001600160a01b031683528281019390935260409182018120600101939093558a835260089091528120600e80548a93919085908110612da457612da4615b26565b60009182526020808320909101546001600160a01b0316835282019290925260400190205580612dd381615b6a565b915050612c7b565b50867fc0cfd54d2de2b55f1e6e108d3ec53ff0a1abe6055401d32c61e9433b747ef9f887604051612e0e91815260200190565b60405180910390a250505050505050565b6011546001600160a01b03163314612e795760405162461bcd60e51b815260206004820152601760248201527f4e6f74206661726d20626f6f737420636f6e74726163740000000000000000006044820152606401611244565b60008281526009602052604090206002810154612ea95760405163079f151f60e11b815260040160405180910390fd5b60005b600e54811015612efc57612ee982600e8381548110612ecd57612ecd615b26565b60009182526020822001546001600160a01b0316908790613f0c565b5080612ef481615b6a565b915050612eac565b50612f0881848461447d565b505050565b6001600160a01b0382166000908152600d6020526040812060010154819015612f83576001600160a01b0384166000818152600d60208181526040808420600181015489865260088452828620968652958352932054919052600690910154612f769190615bf9565b612f809190615c18565b91505b506001600160a01b039092166000908152600d602052604090206005015491929050565b60006001600160a01b0382166130255760405162461bcd60e51b815260206004820152602d60248201527f456e756d657261626c653a2061646472657373207a65726f206973206e6f742060448201527f612076616c6964206f776e6572000000000000000000000000000000000000006064820152608401611244565b506001600160a01b031660009081526003602052604090205490565b613049614296565b6130536000614e0c565b565b61305d614296565b6001600160a01b0381166130845760405163d92e233d60e01b815260040160405180910390fd5b60005b600e5481101561314057600019600e82815481106130a7576130a7615b26565b600091825260209091200154604051636eb1769f60e11b81526001600160a01b0385811660048301523060248301529091169063dd62ed3e90604401602060405180830381865afa158015613100573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131249190615d8a565b1461312e57600080fd5b8061313881615b6a565b915050613087565b50600f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f4a2963bfc20b87a0c055468a66e6638d57725e93fb4d65733fb2f25587ae8c4f906020016111e3565b60015433906001600160a01b031681146131fd5760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b6064820152608401611244565b6129be81614e0c565b6001600160a01b0382166000908152600d6020526040812060010154819015612f83576001600160a01b038085166000818152600d602081815260408084206001810154968a168552600c835281852054855260088352818520958552948252909220549152600690910154612f769190615bf9565b600e818154811061328c57600080fd5b6000918252602090912001546001600160a01b0316905081565b6132ae614296565b620151808110806132c1575062278d0081115b156132df57604051634f08daf360e11b815260040160405180910390fd5b60138190556040518181527fb5521c8a03b484502769158d9dd83186bd0748f3ece2fbf358233994c2a20976906020016111e3565b60608167ffffffffffffffff81111561332f5761332f6154f3565b60405190808252806020026020018201604052801561336257816020015b606081526020019060019003908161334d5790505b50905060005b82811015613465576000803086868581811061338657613386615b26565b90506020028101906133989190615e19565b6040516133a6929190615e60565b600060405180830381855af49150503d80600081146133e1576040519150601f19603f3d011682016040523d82523d6000602084013e6133e6565b606091505b509150915081613432576044815110156133ff57600080fd5b600481019050808060200190518101906134199190615e70565b60405162461bcd60e51b81526004016112449190615f04565b8084848151811061344557613445615b26565b60200260200101819052505050808061345d90615b6a565b915050613368565b5092915050565b613474614296565b6001600160a01b03811661349b5760405163d92e233d60e01b815260040160405180910390fd5b601280546001600160a01b0319166001600160a01b0383169081179091556040519081527fc47d127c07bdd56c5ccba00463ce3bd3c1bca71b4670eea6e5d0c02e4aa156e2906020016111e3565b6060600e80548060200260200160405190810160405280929190818152602001828054801561354157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311613523575b5050505050905090565b613553613eb4565b600081815260096020526040902060028101546135835760405163079f151f60e11b815260040160405180910390fd5b60005b600e548110156135d6576135c382600e83815481106135a7576135a7615b26565b60009182526020822001546001600160a01b0316908690613f0c565b50806135ce81615b6a565b915050613586565b506135e38183600061447d565b506129be6001600255565b6135f6614296565b6001600160a01b03811661361d5760405163d92e233d60e01b815260040160405180910390fd5b601080546001600160a01b0319166001600160a01b0383169081179091556040519081527f29e3e57b4a1e4513d009781598c7e4b8b2a68e4b71fe977e362d1b591016fade906020016111e3565b613673614296565b601180546001600160a01b0319166001600160a01b0383169081179091556040517ff32244aa081c72b930bb47bb702115e112d779ed353d6b1a70b28babc9822b7a90600090a250565b6136c5613eb4565b6040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa15801561370c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137309190615d8a565b905060005b600e5481101561382557600e818154811061375257613752615b26565b6000918252602090912001546001600160a01b03868116911614156137d8576001600160a01b0385166000908152600d602052604090206002015482106137b8576001600160a01b0385166000908152600d6020526040902060020154909103906137d8565b6001600160a01b0385166000908152600d60205260408120600201929092555b838210156137f957604051632ca2f52b60e11b815260040160405180910390fd5b8115613813576138136001600160a01b0386168484614e25565b8061381d81615b6a565b915050613735565b5050612f086001600255565b613839613eb4565b6040516370a0823160e01b81523060048201526000907f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b0316906370a0823190602401602060405180830381865afa1580156138a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138c49190615d8a565b9050828110156138e757604051632ca2f52b60e11b815260040160405180910390fd5b801561397157604051632e1a7d4d60e01b8152600481018290527f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561394f57600080fd5b505af1158015613963573d6000803e3d6000fd5b505050506139718282614e55565b5061397c6001600255565b5050565b613988614296565b600180546001600160a01b0383166001600160a01b031990911681179091556139b96000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000818152600960209081526040808320815160e08101835281546001600160801b038082168352600160801b90910416938101939093526001810154600281810b9385019390935263010000008104830b6060850152600160301b90046001600160a01b031660808401529081015460a0830181905260039091015460c0830152156134655760a0818101516000908152600760209081526040808320815160c08101835281546001600160a01b039081168083526001840154821683870152600284015491821683860152600160a01b90910462ffffff16606083015260038301546080830152600492830154968201969096528251630a81a92360e31b8152925190959363540d49189380840193919291908290030181865afa158015613b1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613b439190615b95565b90506001600160a01b03811615613c3357604083810151606085015191516301e72ef560e71b81526001600160a01b038981166004830152600292830b60248301529290910b604482015260009183169063f3977a8090606401602060405180830381865afa158015613bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bde9190615d8a565b6000878152600a602090815260408083206001600160a01b038c16845282529091205490860151919250820390600160801b90613c24906001600160801b031683615bf9565b613c2e9190615c18565b955050505b6000858152600a602090815260408083206001600160a01b038a168452909152902060010154613c639085615b52565b9695505050505050565b6000613c77613eb4565b60008381526009602052604090206001810154600160301b90046001600160a01b03163314613cb9576040516330cd747160e01b815260040160405180910390fd5b80546001600160801b0316158015613cf457506000848152600a602090815260408083206001600160a01b0389168452909152902060010154155b15613d1257604051636180f03f60e11b815260040160405180910390fd5b613d1e81868686613f0c565b915050613d2b6001600255565b9392505050565b600080613d3d613eb4565b825160009081526009602052604090206001810154600160301b90046001600160a01b03163314613d81576040516330cd747160e01b815260040160405180910390fd5b60208401516001600160a01b0316613d9a573060208501525b6040805163fc6f786560e01b81528551600482015260208601516001600160a01b039081166024830152918601516001600160801b03908116604483015260608701511660648201527f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b9091169063fc6f78659060840160408051808303816000875af1158015613e2f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e539190615c3a565b90935091506115e790506001600255565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600280541415613f065760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611244565b60028055565b6002848101546000908152600760209081526040808320815160c08101835281546001600160a01b0390811680835260018401548216838701529683015490811682850152600160a01b900462ffffff1660608201526003820154608082015260049182015460a08201528251630a81a92360e31b81529251949590948694919363540d4918938181019392918290030181865afa158015613fb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd69190615b95565b90506001600160a01b03811615801590613ffa5750601154600160a01b900460ff16155b15614165576040516310a537f160e11b815263ffffffff421660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b15801561404657600080fd5b505af115801561405a573d6000803e3d6000fd5b5050505060018701546040516301e72ef560e71b81526001600160a01b038881166004830152600283810b6024840152630100000090930490920b604482015260009183169063f3977a8090606401602060405180830381865afa1580156140c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140ea9190615d8a565b6000878152600a602090815260408083206001600160a01b038c1684529091529020548954919250820390600160801b90614131908290046001600160801b031683615bf9565b61413b9190615c18565b6000888152600a602090815260408083206001600160a01b038d1684529091529020929092555092505b6000858152600a602090815260408083206001600160a01b038a1684529091529020600101546141959084615b52565b92508215614260576001600160a01b03841615614237576000858152600a602090815260408083206001600160a01b038a1684529091528120600101556141dd868585614eb5565b6002870154604080516001600160a01b0387811682528916602082015290810185905286919033907f282b9c6f6d6a6b0d9b4175a3af0be477af589c6cb2d91400d87972ef449876d79060600160405180910390a4614260565b6000858152600a602090815260408083206001600160a01b038a16845290915290206001018390555b5050949350505050565b6142748282614fb3565b506001600160a01b031660009081526003602052604090208054600019019055565b6000546001600160a01b031633146130535760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611244565b6040516001600160a01b0380851660248301528316604482015260648101829052612b419085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909316929092179091526150cd565b4260015b600654811161397c57600081815260076020908152604080832080548251630a81a92360e31b815292519194936001600160a01b039091169263540d491892600480830193928290030181865afa1580156143d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143f79190615b95565b90506001600160a01b03811615614468576040516310a537f160e11b815263ffffffff851660048201526001600160a01b0382169063214a6fe290602401600060405180830381600087803b15801561444f57600080fd5b505af1158015614463573d6000803e3d6000fd5b505050505b5050808061447590615b6a565b915050614374565b60008060007f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b6001600160a01b03166399fbab88866040518263ffffffff1660e01b81526004016144d091815260200190565b61018060405180830381865afa1580156144ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145129190615c8e565b5050505060028e015460009081526007602052604090208e54939b50919950975095506001600160801b03808816911614935061459e9250505057865460038201546001600160801b038085169261456c92911690615be2565b6145769190615b52565b600382015586546fffffffffffffffffffffffffffffffff19166001600160801b0383161787555b60115464e8d4a51000906001600160a01b0316158015906145bd575085155b1561463857601154604051632273df8360e11b8152600481018990526001600160a01b03909116906344e7bf06906024016020604051808303816000875af115801561460d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146319190615d8a565b9050614641565b85156146415750845b64e8d4a5100081101561465a575064e8d4a51000614671565b6501d1a94a200081111561467157506501d1a94a20005b6003880181905560006146a564e8d4a51000614696846001600160801b038816615bf9565b6146a09190615c18565b6151b5565b89549091506000906146c790600160801b90046001600160801b031683615f17565b905080600f0b60001461499057895460048501546001600160801b03808516926146fc92600160801b90910490911690615be2565b6147069190615b52565b6004808601919091558a546001600160801b03808516600160801b029116178b55845460408051630a81a92360e31b815290516000936001600160a01b039093169263540d4918928082019260209290918290030181865afa158015614770573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147949190615b95565b90506001600160a01b0381166147bd5760405163ef3d9b2160e01b815260040160405180910390fd5b604051638910faf160e01b8152600289810b600483015288900b6024820152600f83900b60448201526001600160a01b03821690638910faf190606401600060405180830381600087803b15801561481457600080fd5b505af1158015614828573d6000803e3d6000fd5b5050505060005b600e5481101561493d57816001600160a01b031663f3977a80600e838154811061485b5761485b615b26565b60009182526020909120015460405160e083901b6001600160e01b03191681526001600160a01b03909116600482015260028c810b60248301528b900b6044820152606401602060405180830381865afa1580156148bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148e19190615d8a565b60008c8152600a60205260408120600e80549192918590811061490657614906615b26565b60009182526020808320909101546001600160a01b031683528201929092526040019020558061493581615b6a565b91505061482f565b5060028b81015460408051600f86900b81528b840b6020820152928a900b83820152518c9233917fee8f6362d59839b4b3c990d7e085a63a0fe2c58f4eff4a9a2b6de93a4c645ae39181900360600190a4505b50505050505050505050565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156149e3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614a079190615d8a565b905060005b600e54811015612b4157600e8181548110614a2957614a29615b26565b6000918252602090912001546001600160a01b0385811691161415614aaf576001600160a01b0384166000908152600d60205260409020600201548210614a8f576001600160a01b0384166000908152600d602052604090206002015490910390614aaf565b6001600160a01b0384166000908152600d60205260408120600201929092555b8115614b8c577f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b0316846001600160a01b03161415614b7857604051632e1a7d4d60e01b8152600481018390527f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015614b5157600080fd5b505af1158015614b65573d6000803e3d6000fd5b50505050614b738383614e55565b614b8c565b614b8c6001600160a01b0385168484614e25565b80614b9681615b6a565b915050614a0c565b801580614c185750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015614bf2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614c169190615d8a565b155b614c8a5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401611244565b6040516001600160a01b038316602482015260448101829052612f0890849063095ea7b360e01b90606401614324565b7f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b0316826001600160a01b0316148015614cfb5750600034115b15614d205780341461397c57604051634b508fef60e01b815260040160405180910390fd5b61397c6001600160a01b0383163330846142f0565b7f0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a6001600160a01b0316826001600160a01b0316148015614d765750600034115b15614df8577f0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b6001600160a01b0316631f9709826040518163ffffffff1660e01b8152600401600060405180830381600087803b158015614dd657600080fd5b505af1158015614dea573d6000803e3d6000fd5b5050505061397c3347614e55565b61397c6001600160a01b0383163383614e25565b600180546001600160a01b03191690556129be81613e64565b6040516001600160a01b038316602482015260448101829052612f0890849063a9059cbb60e01b90606401614324565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114614ea2576040519150601f19603f3d011682016040523d82523d6000602084013e614ea7565b606091505b5050905080612f0857600080fd5b8015612f08576040516370a0823160e01b81523060048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015614f02573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f269190615d8a565b905081811015614f34578091505b6001600160a01b0384166000908152600d60205260409020600201548211614f7d576001600160a01b0384166000908152600d6020526040902060020180548390039055614f9f565b6001600160a01b0384166000908152600d602052604090208282036002909101555b612b416001600160a01b0385168484614e25565b6001600160a01b038216600090815260036020526040812054614fd890600190615be2565b6000838152600560209081526040808320546001600160a01b038816845260048352818420818552909252909120549192509083146150595760405162461bcd60e51b815260206004820152600f60248201527f496e76616c696420746f6b656e496400000000000000000000000000000000006044820152606401611244565b81811461509a576001600160a01b03841660009081526004602090815260408083208584528252808320548484528184208190558352600590915290208190555b5060009182526005602090815260408084208490556001600160a01b039094168352600481528383209183525290812055565b6000615122826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661521e9092919063ffffffff16565b90508051600014806151435750808060200190518101906151439190615f79565b612f085760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401611244565b6000600160801b821061521a5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b6064820152608401611244565b5090565b606061522d8484600085615235565b949350505050565b6060824710156152965760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401611244565b600080866001600160a01b031685876040516152b29190615f96565b60006040518083038185875af1925050503d80600081146152ef576040519150601f19603f3d011682016040523d82523d6000602084013e6152f4565b606091505b509150915061530587838387615310565b979650505050505050565b6060831561537c578251615375576001600160a01b0385163b6153755760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401611244565b508161522d565b61522d83838151156153915781518083602001fd5b8060405162461bcd60e51b81526004016112449190615f04565b828054828255906000526020600020908101928215615400579160200282015b8281111561540057825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906153cb565b5061521a9291505b8082111561521a5760008155600101615408565b6001600160a01b03811681146129be57600080fd5b6000806040838503121561544457600080fd5b8235915060208301356154568161541c565b809150509250929050565b80151581146129be57600080fd5b60006020828403121561548157600080fd5b8135613d2b81615461565b600080600080608085870312156154a257600080fd5b84356154ad8161541c565b9350602085013592506040850135915060608501356154cb81615461565b939692955090935050565b6000602082840312156154e857600080fd5b8135613d2b8161541c565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715615532576155326154f3565b604052919050565b6001600160801b03811681146129be57600080fd5b600060a0828403121561556157600080fd5b60405160a0810181811067ffffffffffffffff82111715615584576155846154f3565b6040528235815260208301356155998161553a565b806020830152506040830135604082015260608301356060820152608083013560808201528091505092915050565b6000608082840312156155da57600080fd5b6040516080810181811067ffffffffffffffff821117156155fd576155fd6154f3565b6040528235815290508060208301356156158161541c565b602082015260408301356156288161553a565b6040820152606083013561563b8161553a565b6060919091015292915050565b60008060a0838503121561565b57600080fd5b61566584846155c8565b915060808301356154568161541c565b60008060008060006080868803121561568d57600080fd5b85356156988161541c565b945060208601356156a88161541c565b935060408601359250606086013567ffffffffffffffff808211156156cc57600080fd5b818801915088601f8301126156e057600080fd5b8135818111156156ef57600080fd5b89602082850101111561570157600080fd5b9699959850939650602001949392505050565b60006020828403121561572657600080fd5b5035919050565b60008060006060848603121561574257600080fd5b8335925060208401356157548161541c565b9150604084013561576481615461565b809150509250925092565b6000602080838503121561578257600080fd5b823567ffffffffffffffff8082111561579a57600080fd5b818501915085601f8301126157ae57600080fd5b8135818111156157c0576157c06154f3565b8060051b91506157d1848301615509565b81815291830184019184810190888411156157eb57600080fd5b938501935b8385101561581557843592506158058361541c565b82825293850193908501906157f0565b98975050505050505050565b600060c0828403121561583357600080fd5b60405160c0810181811067ffffffffffffffff82111715615856576158566154f3565b8060405250823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a08201528091505092915050565b600080604083850312156158ae57600080fd5b82356158b98161541c565b946020939093013593505050565b60008083601f8401126158d957600080fd5b50813567ffffffffffffffff8111156158f157600080fd5b6020830191508360208260051b850101111561178957600080fd5b6000806020838503121561591f57600080fd5b823567ffffffffffffffff81111561593657600080fd5b615942858286016158c7565b90969095509350505050565b60008060006060848603121561596357600080fd5b8335925060208401359150604084013561576481615461565b6000806040838503121561598f57600080fd5b50508035926020909101359150565b600080604083850312156159b157600080fd5b82356159bc8161541c565b915060208301356154568161541c565b60005b838110156159e75781810151838201526020016159cf565b83811115612b415750506000910152565b60008151808452615a108160208601602086016159cc565b601f01601f19169290920160200192915050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015615a7957603f19888603018452615a678583516159f8565b94509285019290850190600101615a4b565b5092979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015615ac75783516001600160a01b031683529284019291840191600101615aa2565b50909695505050505050565b600080600060608486031215615ae857600080fd5b8335615af38161541c565b92506020840135915060408401356157648161541c565b600060808284031215615b1c57600080fd5b613d2b83836155c8565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008219821115615b6557615b65615b3c565b500190565b6000600019821415615b7e57615b7e615b3c565b5060010190565b8051615b908161541c565b919050565b600060208284031215615ba757600080fd5b8151613d2b8161541c565b600081600f0b6f7fffffffffffffffffffffffffffffff19811415615bd957615bd9615b3c565b60000392915050565b600082821015615bf457615bf4615b3c565b500390565b6000816000190483118215151615615c1357615c13615b3c565b500290565b600082615c3557634e487b7160e01b600052601260045260246000fd5b500490565b60008060408385031215615c4d57600080fd5b505080516020909101519092909150565b805162ffffff81168114615b9057600080fd5b8051600281900b8114615b9057600080fd5b8051615b908161553a565b6000806000806000806000806000806000806101808d8f031215615cb157600080fd5b8c516bffffffffffffffffffffffff81168114615ccd57600080fd5b9b50615cdb60208e01615b85565b9a50615ce960408e01615b85565b9950615cf760608e01615b85565b9850615d0560808e01615c5e565b9750615d1360a08e01615c71565b9650615d2160c08e01615c71565b9550615d2f60e08e01615c83565b94506101008d015193506101208d01519250615d4e6101408e01615c83565b9150615d5d6101608e01615c83565b90509295989b509295989b509295989b565b600060208284031215615d8157600080fd5b613d2b82615c5e565b600060208284031215615d9c57600080fd5b5051919050565b815160009082906020808601845b83811015615dd65781516001600160a01b031685529382019390820190600101615db1565b50929695505050505050565b600080600060608486031215615df757600080fd5b8351615e028161553a565b602085015160409095015190969495509392505050565b6000808335601e19843603018112615e3057600080fd5b83018035915067ffffffffffffffff821115615e4b57600080fd5b60200191503681900382131561178957600080fd5b8183823760009101908152919050565b600060208284031215615e8257600080fd5b815167ffffffffffffffff80821115615e9a57600080fd5b818401915084601f830112615eae57600080fd5b815181811115615ec057615ec06154f3565b615ed3601f8201601f1916602001615509565b9150808252856020828501011115615eea57600080fd5b615efb8160208401602086016159cc565b50949350505050565b602081526000613d2b60208301846159f8565b600081600f0b83600f0b60008112816f7fffffffffffffffffffffffffffffff1901831281151615615f4b57615f4b615b3c565b816f7fffffffffffffffffffffffffffffff018313811615615f6f57615f6f615b3c565b5090039392505050565b600060208284031215615f8b57600080fd5b8151613d2b81615461565b60008251615fa88184602087016159cc565b919091019291505056fea2646970667358221220dccd53a6d7511cc0a8716e3a35993a353d895644768beec42ee9dbb63a20154c64736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000600000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a00000000000000000000000000000000000000000000000000000000000000010000000000000000000000001516000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _rewardTokens (address[]): 0x1516000000000000000000000000000000000000
Arg [1] : _nonfungiblePositionManager (address): 0x2756220030E954B39cc9d341b519732696f7EE0B
Arg [2] : _WIP (address): 0x1Ed1daB171dAe0092e798373370b335704C5321A
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 0000000000000000000000002756220030e954b39cc9d341b519732696f7ee0b
Arg [2] : 0000000000000000000000001ed1dab171dae0092e798373370b335704c5321a
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [4] : 0000000000000000000000001516000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ 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.