Polygon Sponsored slots available. Book your slot here!
Contract Overview
[ Download CSV Export ]
Contract Name:
PopLocker
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0 // Docgen-SOLC: 0.6.0 import "openzeppelin-v3/token/ERC20/IERC20.sol"; import "openzeppelin-v3/token/ERC20/SafeERC20.sol"; import "openzeppelin-v3/math/Math.sol"; import "openzeppelin-v3/access/Ownable.sol"; import "openzeppelin-v3/utils/ReentrancyGuard.sol"; import "../libraries/BoringMath.sol"; import "../interfaces/IRewardsEscrow.sol"; pragma solidity 0.6.12; pragma experimental ABIEncoderV2; // POP locked in this contract will be entitled to voting rights for popcorn.network // Based on CVX Locking contract for https://www.convexfinance.com/ // Based on EPS Staking contract for http://ellipsis.finance/ // Based on SNX MultiRewards by iamdefinitelyahuman - https://github.com/iamdefinitelyahuman/multi-rewards contract PopLocker is ReentrancyGuard, Ownable { using BoringMath for uint256; using BoringMath224 for uint224; using BoringMath112 for uint112; using BoringMath32 for uint32; using SafeERC20 for IERC20; /* ========== STATE VARIABLES ========== */ struct Reward { bool useBoost; uint40 periodFinish; uint208 rewardRate; uint40 lastUpdateTime; uint208 rewardPerTokenStored; } struct Balances { uint112 locked; uint112 boosted; uint32 nextUnlockIndex; } struct LockedBalance { uint112 amount; uint112 boosted; uint32 unlockTime; } struct EarnedData { address token; uint256 amount; } struct Epoch { uint224 supply; //epoch boosted supply uint32 date; //epoch start date } //token constants IERC20 public stakingToken; IRewardsEscrow public rewardsEscrow; //rewards address[] public rewardTokens; mapping(address => Reward) public rewardData; // duration in seconds for rewards to be held in escrow uint256 public escrowDuration; // Duration that rewards are streamed over uint256 public constant rewardsDuration = 7 days; // Duration of lock/earned penalty period uint256 public constant lockDuration = rewardsDuration * 12; // reward token -> distributor -> is approved to add rewards mapping(address => mapping(address => bool)) public rewardDistributors; // user -> reward token -> amount mapping(address => mapping(address => uint256)) public userRewardPerTokenPaid; mapping(address => mapping(address => uint256)) public rewards; //supplies and epochs uint256 public lockedSupply; uint256 public boostedSupply; Epoch[] public epochs; //mappings for balance data mapping(address => Balances) public balances; mapping(address => LockedBalance[]) public userLocks; //boost address public boostPayment; uint256 public maximumBoostPayment = 0; uint256 public boostRate = 10000; uint256 public nextMaximumBoostPayment = 0; uint256 public nextBoostRate = 10000; uint256 public constant denominator = 10000; //management uint256 public kickRewardPerEpoch = 100; uint256 public kickRewardEpochDelay = 4; //shutdown bool public isShutdown = false; //erc20-like interface string private _name; string private _symbol; uint8 private immutable _decimals; /* ========== CONSTRUCTOR ========== */ constructor(IERC20 _stakingToken, IRewardsEscrow _rewardsEscrow) public Ownable() { _name = "Vote Locked POP Token"; _symbol = "vlPOP"; _decimals = 18; stakingToken = _stakingToken; rewardsEscrow = _rewardsEscrow; escrowDuration = 365 days; uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); epochs.push(Epoch({ supply: 0, date: uint32(currentEpoch) })); } function decimals() public view returns (uint8) { return _decimals; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } /* ========== ADMIN CONFIGURATION ========== */ // Add a new reward token to be distributed to stakers function addReward( address _rewardsToken, address _distributor, bool _useBoost ) public onlyOwner { require(rewardData[_rewardsToken].lastUpdateTime == 0); rewardTokens.push(_rewardsToken); rewardData[_rewardsToken].lastUpdateTime = uint40(block.timestamp); rewardData[_rewardsToken].periodFinish = uint40(block.timestamp); rewardData[_rewardsToken].useBoost = _useBoost; rewardDistributors[_rewardsToken][_distributor] = true; } // Modify approval for an address to call notifyRewardAmount function approveRewardDistributor( address _rewardsToken, address _distributor, bool _approved ) external onlyOwner { require(rewardData[_rewardsToken].lastUpdateTime > 0, "rewards token does not exist"); rewardDistributors[_rewardsToken][_distributor] = _approved; } //set boost parameters function setBoost( uint256 _max, uint256 _rate, address _receivingAddress ) external onlyOwner { require(_max < 1500, "over max payment"); //max 15% require(_rate < 30000, "over max rate"); //max 3x require(_receivingAddress != address(0), "invalid address"); //must point somewhere valid nextMaximumBoostPayment = _max; nextBoostRate = _rate; boostPayment = _receivingAddress; } function setEscrowDuration(uint256 duration) external onlyOwner { emit EscrowDurationUpdated(escrowDuration, duration); escrowDuration = duration; } //set kick incentive function setKickIncentive(uint256 _rate, uint256 _delay) external onlyOwner { require(_rate <= 500, "over max rate"); //max 5% per epoch require(_delay >= 2, "min delay"); //minimum 2 epochs of grace kickRewardPerEpoch = _rate; kickRewardEpochDelay = _delay; } //shutdown the contract. function shutdown() external onlyOwner { isShutdown = true; } //set approvals for rewards escrow function setApprovals() external { IERC20(stakingToken).safeApprove(address(rewardsEscrow), 0); IERC20(stakingToken).safeApprove(address(rewardsEscrow), uint256(-1)); } /* ========== VIEWS ========== */ function _rewardPerToken(address _rewardsToken) internal view returns (uint256) { if (boostedSupply == 0) { return rewardData[_rewardsToken].rewardPerTokenStored; } return uint256(rewardData[_rewardsToken].rewardPerTokenStored).add( _lastTimeRewardApplicable(rewardData[_rewardsToken].periodFinish) .sub(rewardData[_rewardsToken].lastUpdateTime) .mul(rewardData[_rewardsToken].rewardRate) .mul(1e18) .div(rewardData[_rewardsToken].useBoost ? boostedSupply : lockedSupply) ); } function _earned( address _user, address _rewardsToken, uint256 _balance ) internal view returns (uint256) { return _balance.mul(_rewardPerToken(_rewardsToken).sub(userRewardPerTokenPaid[_user][_rewardsToken])).div(1e18).add( rewards[_user][_rewardsToken] ); } function _lastTimeRewardApplicable(uint256 _finishTime) internal view returns (uint256) { return Math.min(block.timestamp, _finishTime); } function lastTimeRewardApplicable(address _rewardsToken) public view returns (uint256) { return _lastTimeRewardApplicable(rewardData[_rewardsToken].periodFinish); } function rewardPerToken(address _rewardsToken) external view returns (uint256) { return _rewardPerToken(_rewardsToken); } function getRewardForDuration(address _rewardsToken) external view returns (uint256) { return uint256(rewardData[_rewardsToken].rewardRate).mul(rewardsDuration); } // Address and claimable amount of all reward tokens for the given account function claimableRewards(address _account) external view returns (EarnedData[] memory userRewards) { userRewards = new EarnedData[](rewardTokens.length); Balances storage userBalance = balances[_account]; uint256 boostedBal = userBalance.boosted; for (uint256 i = 0; i < userRewards.length; i++) { address token = rewardTokens[i]; userRewards[i].token = token; userRewards[i].amount = _earned(_account, token, rewardData[token].useBoost ? boostedBal : userBalance.locked); } return userRewards; } // Total BOOSTED balance of an account, including unlocked but not withdrawn tokens function rewardWeightOf(address _user) external view returns (uint256 amount) { return balances[_user].boosted; } // total token balance of an account, including unlocked but not withdrawn tokens function lockedBalanceOf(address _user) external view returns (uint256 amount) { return balances[_user].locked; } //BOOSTED balance of an account which only includes properly locked tokens as of the most recent eligible epoch function balanceOf(address _user) external view returns (uint256 amount) { LockedBalance[] storage locks = userLocks[_user]; Balances storage userBalance = balances[_user]; uint256 nextUnlockIndex = userBalance.nextUnlockIndex; //start with current boosted amount amount = balances[_user].boosted; uint256 locksLength = locks.length; //remove old records only (will be better gas-wise than adding up) for (uint256 i = nextUnlockIndex; i < locksLength; i++) { if (locks[i].unlockTime <= block.timestamp) { amount = amount.sub(locks[i].boosted); } else { //stop now as no futher checks are needed break; } } //also remove amount in the current epoch uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); if (locksLength > 0 && uint256(locks[locksLength - 1].unlockTime).sub(lockDuration) == currentEpoch) { amount = amount.sub(locks[locksLength - 1].boosted); } return amount; } //BOOSTED balance of an account which only includes properly locked tokens at the given epoch function balanceAtEpochOf(uint256 _epoch, address _user) external view returns (uint256 amount) { LockedBalance[] storage locks = userLocks[_user]; //get timestamp of given epoch index uint256 epochTime = epochs[_epoch].date; //get timestamp of first non-inclusive epoch uint256 cutoffEpoch = epochTime.sub(lockDuration); //current epoch is not counted uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); //need to add up since the range could be in the middle somewhere //traverse inversely to make more current queries more gas efficient for (uint256 i = locks.length - 1; i + 1 != 0; i--) { uint256 lockEpoch = uint256(locks[i].unlockTime).sub(lockDuration); //lock epoch must be less or equal to the epoch we're basing from. //also not include the current epoch if (lockEpoch <= epochTime && lockEpoch < currentEpoch) { if (lockEpoch > cutoffEpoch) { amount = amount.add(locks[i].boosted); } else { //stop now as no futher checks matter break; } } } return amount; } //supply of all properly locked BOOSTED balances at most recent eligible epoch function totalSupply() external view returns (uint256 supply) { uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); uint256 cutoffEpoch = currentEpoch.sub(lockDuration); uint256 epochindex = epochs.length; //do not include current epoch's supply if (uint256(epochs[epochindex - 1].date) == currentEpoch) { epochindex--; } //traverse inversely to make more current queries more gas efficient for (uint256 i = epochindex - 1; i + 1 != 0; i--) { Epoch storage e = epochs[i]; if (uint256(e.date) <= cutoffEpoch) { break; } supply = supply.add(e.supply); } return supply; } //supply of all properly locked BOOSTED balances at the given epoch function totalSupplyAtEpoch(uint256 _epoch) external view returns (uint256 supply) { uint256 epochStart = uint256(epochs[_epoch].date).div(rewardsDuration).mul(rewardsDuration); uint256 cutoffEpoch = epochStart.sub(lockDuration); uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); //do not include current epoch's supply if (uint256(epochs[_epoch].date) == currentEpoch) { _epoch--; } //traverse inversely to make more current queries more gas efficient for (uint256 i = _epoch; i + 1 != 0; i--) { Epoch storage e = epochs[i]; if (uint256(e.date) <= cutoffEpoch) { break; } supply = supply.add(epochs[i].supply); } return supply; } //find an epoch index based on timestamp function findEpochId(uint256 _time) external view returns (uint256 epoch) { uint256 max = epochs.length - 1; uint256 min = 0; //convert to start point _time = _time.div(rewardsDuration).mul(rewardsDuration); for (uint256 i = 0; i < 128; i++) { if (min >= max) break; uint256 mid = (min + max + 1) / 2; uint256 midEpochBlock = epochs[mid].date; if (midEpochBlock == _time) { //found return mid; } else if (midEpochBlock < _time) { min = mid; } else { max = mid - 1; } } return min; } // Information on a user's locked balances function lockedBalances(address _user) external view returns ( uint256 total, uint256 unlockable, uint256 locked, LockedBalance[] memory lockData ) { LockedBalance[] storage locks = userLocks[_user]; Balances storage userBalance = balances[_user]; uint256 nextUnlockIndex = userBalance.nextUnlockIndex; uint256 idx; for (uint256 i = nextUnlockIndex; i < locks.length; i++) { if (locks[i].unlockTime > block.timestamp) { if (idx == 0) { lockData = new LockedBalance[](locks.length - i); } lockData[idx] = locks[i]; idx++; locked = locked.add(locks[i].amount); } else { unlockable = unlockable.add(locks[i].amount); } } return (userBalance.locked, unlockable, locked, lockData); } //number of epochs function epochCount() external view returns (uint256) { return epochs.length; } /* ========== MUTATIVE FUNCTIONS ========== */ function checkpointEpoch() external { _checkpointEpoch(); } //insert a new epoch if needed. fill in any gaps function _checkpointEpoch() internal { uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); uint256 epochindex = epochs.length; //first epoch add in constructor, no need to check 0 length //check to add if (epochs[epochindex - 1].date < currentEpoch) { //fill any epoch gaps while (epochs[epochs.length - 1].date != currentEpoch) { uint256 nextEpochDate = uint256(epochs[epochs.length - 1].date).add(rewardsDuration); epochs.push(Epoch({ supply: 0, date: uint32(nextEpochDate) })); } //update boost parameters on a new epoch if (boostRate != nextBoostRate) { boostRate = nextBoostRate; } if (maximumBoostPayment != nextMaximumBoostPayment) { maximumBoostPayment = nextMaximumBoostPayment; } } } // Locked tokens cannot be withdrawn for lockDuration and are eligible to receive stakingReward rewards function lock( address _account, uint256 _amount, uint256 _spendRatio ) external nonReentrant { //pull tokens stakingToken.safeTransferFrom(msg.sender, address(this), _amount); //lock _lock(_account, _amount, _spendRatio); } //lock tokens function _lock( address _account, uint256 _amount, uint256 _spendRatio ) internal updateReward(_account) { require(_amount > 0, "Cannot stake 0"); require(_spendRatio <= maximumBoostPayment, "over max spend"); require(!isShutdown, "shutdown"); Balances storage bal = balances[_account]; //must try check pointing epoch first _checkpointEpoch(); //calc lock and boosted amount uint256 spendAmount = _amount.mul(_spendRatio).div(denominator); uint256 boostRatio = boostRate.mul(_spendRatio).div(maximumBoostPayment == 0 ? 1 : maximumBoostPayment); uint112 lockAmount = _amount.sub(spendAmount).to112(); uint112 boostedAmount = _amount.add(_amount.mul(boostRatio).div(denominator)).to112(); //add user balances bal.locked = bal.locked.add(lockAmount); bal.boosted = bal.boosted.add(boostedAmount); //add to total supplies lockedSupply = lockedSupply.add(lockAmount); boostedSupply = boostedSupply.add(boostedAmount); //add user lock records or add to current uint256 currentEpoch = block.timestamp.div(rewardsDuration).mul(rewardsDuration); uint256 unlockTime = currentEpoch.add(lockDuration); uint256 idx = userLocks[_account].length; if (idx == 0 || userLocks[_account][idx - 1].unlockTime < unlockTime) { userLocks[_account].push( LockedBalance({ amount: lockAmount, boosted: boostedAmount, unlockTime: uint32(unlockTime) }) ); } else { LockedBalance storage userL = userLocks[_account][idx - 1]; userL.amount = userL.amount.add(lockAmount); userL.boosted = userL.boosted.add(boostedAmount); } //update epoch supply, epoch checkpointed above so safe to add to latest Epoch storage e = epochs[epochs.length - 1]; e.supply = e.supply.add(uint224(boostedAmount)); //send boost payment if (spendAmount > 0) { stakingToken.safeTransfer(boostPayment, spendAmount); } emit Staked(_account, _amount, lockAmount, boostedAmount); } // Withdraw all currently locked tokens where the unlock time has passed function _processExpiredLocks( address _account, bool _relock, uint256 _spendRatio, address _withdrawTo, address _rewardAddress, uint256 _checkDelay ) internal updateReward(_account) { LockedBalance[] storage locks = userLocks[_account]; Balances storage userBalance = balances[_account]; uint112 locked; uint112 boostedAmount; uint256 length = locks.length; uint256 reward = 0; if (isShutdown || locks[length - 1].unlockTime <= block.timestamp.sub(_checkDelay)) { //if time is beyond last lock, can just bundle everything together locked = userBalance.locked; boostedAmount = userBalance.boosted; //dont delete, just set next index userBalance.nextUnlockIndex = length.to32(); //check for kick reward //this wont have the exact reward rate that you would get if looped through //but this section is supposed to be for quick and easy low gas processing of all locks //we'll assume that if the reward was good enough someone would have processed at an earlier epoch if (_checkDelay > 0) { reward = _getDelayAdjustedReward(_checkDelay, locks[length - 1]); } } else { //use a processed index(nextUnlockIndex) to not loop as much //deleting does not change array length uint32 nextUnlockIndex = userBalance.nextUnlockIndex; for (uint256 i = nextUnlockIndex; i < length; i++) { //unlock time must be less or equal to time if (locks[i].unlockTime > block.timestamp.sub(_checkDelay)) break; //add to cumulative amounts locked = locked.add(locks[i].amount); boostedAmount = boostedAmount.add(locks[i].boosted); //check for kick reward //each epoch over due increases reward if (_checkDelay > 0) { reward = reward.add(_getDelayAdjustedReward(_checkDelay, locks[i])); } //set next unlock index nextUnlockIndex++; } //update next unlock index userBalance.nextUnlockIndex = nextUnlockIndex; } require(locked > 0, "no exp locks"); //update user balances and total supplies userBalance.locked = userBalance.locked.sub(locked); userBalance.boosted = userBalance.boosted.sub(boostedAmount); lockedSupply = lockedSupply.sub(locked); boostedSupply = boostedSupply.sub(boostedAmount); //send process incentive if (reward > 0) { //if theres a reward(kicked), it will always be a withdraw only //reduce return amount by the kick reward locked = locked.sub(reward.to112()); //transfer reward stakingToken.safeTransfer(_rewardAddress, reward); emit KickReward(_rewardAddress, _account, reward); } //relock or return to user if (_relock) { _lock(_withdrawTo, locked, _spendRatio); emit Relocked(_account, locked); } else { stakingToken.safeTransfer(_withdrawTo, locked); emit Withdrawn(_account, locked); } } function _getDelayAdjustedReward(uint256 _checkDelay, LockedBalance storage lockedBalance) internal view returns (uint256) { uint256 currentEpoch = block.timestamp.sub(_checkDelay).div(rewardsDuration).mul(rewardsDuration); uint256 epochsover = currentEpoch.sub(uint256(lockedBalance.unlockTime)).div(rewardsDuration); uint256 rRate = Math.min(kickRewardPerEpoch.mul(epochsover + 1), denominator); return uint256(lockedBalance.amount).mul(rRate).div(denominator); } // Withdraw/relock all currently locked tokens where the unlock time has passed function processExpiredLocks( bool _relock, uint256 _spendRatio, address _withdrawTo ) external nonReentrant { _processExpiredLocks(msg.sender, _relock, _spendRatio, _withdrawTo, msg.sender, 0); } // Withdraw/relock all currently locked tokens where the unlock time has passed function processExpiredLocks(bool _relock) external nonReentrant { _processExpiredLocks(msg.sender, _relock, 0, msg.sender, msg.sender, 0); } function kickExpiredLocks(address _account) external nonReentrant { //allow kick after grace period of 'kickRewardEpochDelay' _processExpiredLocks(_account, false, 0, _account, msg.sender, rewardsDuration.mul(kickRewardEpochDelay)); } // Claim all pending rewards function getReward(address _account) public nonReentrant updateReward(_account) { for (uint256 i; i < rewardTokens.length; i++) { address _rewardsToken = rewardTokens[i]; uint256 reward = rewards[_account][_rewardsToken]; if (reward > 0) { rewards[_account][_rewardsToken] = 0; uint256 payout = reward.div(uint256(10)); uint256 escrowed = payout.mul(uint256(9)); IERC20(_rewardsToken).safeTransfer(_account, payout); IRewardsEscrow(rewardsEscrow).lock(_account, escrowed, escrowDuration); emit RewardPaid(_account, _rewardsToken, reward); } } } /* ========== RESTRICTED FUNCTIONS ========== */ function _notifyReward(address _rewardsToken, uint256 _reward) internal { Reward storage rdata = rewardData[_rewardsToken]; if (block.timestamp >= rdata.periodFinish) { rdata.rewardRate = _reward.div(rewardsDuration).to208(); } else { uint256 remaining = uint256(rdata.periodFinish).sub(block.timestamp); uint256 leftover = remaining.mul(rdata.rewardRate); rdata.rewardRate = _reward.add(leftover).div(rewardsDuration).to208(); } rdata.lastUpdateTime = block.timestamp.to40(); rdata.periodFinish = block.timestamp.add(rewardsDuration).to40(); } function notifyRewardAmount(address _rewardsToken, uint256 _reward) external updateReward(address(0)) { require(rewardDistributors[_rewardsToken][msg.sender], "not authorized"); require(_reward > 0, "No reward"); _notifyReward(_rewardsToken, _reward); // handle the transfer of reward tokens via `transferFrom` to reduce the number // of transactions required and ensure correctness of the _reward amount IERC20(_rewardsToken).safeTransferFrom(msg.sender, address(this), _reward); emit RewardAdded(_rewardsToken, _reward); } function setRewardsEscrow(address _rewardsEscrow) external onlyOwner { emit RewardsEscrowUpdated(address(rewardsEscrow), _rewardsEscrow); rewardsEscrow = IRewardsEscrow(_rewardsEscrow); } // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders function recoverERC20(address _tokenAddress, uint256 _tokenAmount) external onlyOwner { require(_tokenAddress != address(stakingToken), "Cannot withdraw staking token"); require(rewardData[_tokenAddress].lastUpdateTime == 0, "Cannot withdraw reward token"); IERC20(_tokenAddress).safeTransfer(owner(), _tokenAmount); emit Recovered(_tokenAddress, _tokenAmount); } /* ========== MODIFIERS ========== */ modifier updateReward(address _account) { { //stack too deep Balances storage userBalance = balances[_account]; uint256 boostedBal = userBalance.boosted; for (uint256 i = 0; i < rewardTokens.length; i++) { address token = rewardTokens[i]; rewardData[token].rewardPerTokenStored = _rewardPerToken(token).to208(); rewardData[token].lastUpdateTime = _lastTimeRewardApplicable(rewardData[token].periodFinish).to40(); if (_account != address(0)) { //check if reward is boostable or not. use boosted or locked balance accordingly rewards[_account][token] = _earned( _account, token, rewardData[token].useBoost ? boostedBal : userBalance.locked ); userRewardPerTokenPaid[_account][token] = rewardData[token].rewardPerTokenStored; } } } _; } /* ========== EVENTS ========== */ event RewardAdded(address indexed _token, uint256 _reward); event RewardsEscrowUpdated(address _previous, address _new); event Staked(address indexed _user, uint256 _paidAmount, uint256 _lockedAmount, uint256 _boostedAmount); event Withdrawn(address indexed _user, uint256 _amount); event Relocked(address indexed _user, uint256 _amount); event EscrowDurationUpdated(uint256 _previousDuration, uint256 _newDuration); event KickReward(address indexed _user, address indexed _kicked, uint256 _reward); event RewardPaid(address indexed _user, address indexed _rewardsToken, uint256 _reward); event Recovered(address _token, uint256 _amount); }
// SPDX-License-Identifier: GPL-3.0 // Docgen-SOLC: 0.8.0 pragma solidity >0.6.0; interface IRewardsEscrow { function lock( address _address, uint256 _amount, uint256 duration ) external; }
// SPDX-License-Identifier: MIT // Docgen-SOLC: 0.6.12 pragma solidity 0.6.12; /// @notice A library for performing overflow-/underflow-safe math, /// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math). library BoringMath { function add(uint256 a, uint256 b) internal pure returns (uint256 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint256 a, uint256 b) internal pure returns (uint256 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow"); } function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "BoringMath: division by zero"); return a / b; } function to128(uint256 a) internal pure returns (uint128 c) { require(a <= uint128(-1), "BoringMath: uint128 Overflow"); c = uint128(a); } function to64(uint256 a) internal pure returns (uint64 c) { require(a <= uint64(-1), "BoringMath: uint64 Overflow"); c = uint64(a); } function to32(uint256 a) internal pure returns (uint32 c) { require(a <= uint32(-1), "BoringMath: uint32 Overflow"); c = uint32(a); } function to40(uint256 a) internal pure returns (uint40 c) { require(a <= uint40(-1), "BoringMath: uint40 Overflow"); c = uint40(a); } function to112(uint256 a) internal pure returns (uint112 c) { require(a <= uint112(-1), "BoringMath: uint112 Overflow"); c = uint112(a); } function to224(uint256 a) internal pure returns (uint224 c) { require(a <= uint224(-1), "BoringMath: uint224 Overflow"); c = uint224(a); } function to208(uint256 a) internal pure returns (uint208 c) { require(a <= uint208(-1), "BoringMath: uint208 Overflow"); c = uint208(a); } function to216(uint256 a) internal pure returns (uint216 c) { require(a <= uint216(-1), "BoringMath: uint216 Overflow"); c = uint216(a); } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128. library BoringMath128 { function add(uint128 a, uint128 b) internal pure returns (uint128 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint128 a, uint128 b) internal pure returns (uint128 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint64. library BoringMath64 { function add(uint64 a, uint64 b) internal pure returns (uint64 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint64 a, uint64 b) internal pure returns (uint64 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint32. library BoringMath32 { function add(uint32 a, uint32 b) internal pure returns (uint32 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint32 a, uint32 b) internal pure returns (uint32 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } function mul(uint32 a, uint32 b) internal pure returns (uint32 c) { require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow"); } function div(uint32 a, uint32 b) internal pure returns (uint32) { require(b > 0, "BoringMath: division by zero"); return a / b; } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint112. library BoringMath112 { function add(uint112 a, uint112 b) internal pure returns (uint112 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint112 a, uint112 b) internal pure returns (uint112 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } function mul(uint112 a, uint112 b) internal pure returns (uint112 c) { require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow"); } function div(uint112 a, uint112 b) internal pure returns (uint112) { require(b > 0, "BoringMath: division by zero"); return a / b; } } /// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint224. library BoringMath224 { function add(uint224 a, uint224 b) internal pure returns (uint224 c) { require((c = a + b) >= b, "BoringMath: Add Overflow"); } function sub(uint224 a, uint224 b) internal pure returns (uint224 c) { require((c = a - b) <= a, "BoringMath: Underflow"); } function mul(uint224 a, uint224 b) internal pure returns (uint224 c) { require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow"); } function div(uint224 a, uint224 b) internal pure returns (uint224) { require(b > 0, "BoringMath: division by zero"); return a / b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 () internal { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = 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"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b > a) return (false, 0); return (true, a - b); } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a / b); } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { if (b == 0) return (false, 0); return (true, a % b); } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by zero"); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: modulo by zero"); return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); return a - b; } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryDiv}. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "./IERC20.sol"; import "../../math/SafeMath.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 SafeMath for uint256; using Address for address; function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20 token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require((value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.2 <0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 GSN 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 payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <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 () internal { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IERC20","name":"_stakingToken","type":"address"},{"internalType":"contract IRewardsEscrow","name":"_rewardsEscrow","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_previousDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newDuration","type":"uint256"}],"name":"EscrowDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_kicked","type":"address"},{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"KickReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Recovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Relocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"RewardAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_rewardsToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"RewardPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_previous","type":"address"},{"indexed":false,"internalType":"address","name":"_new","type":"address"}],"name":"RewardsEscrowUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_paidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_lockedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_boostedAmount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"address","name":"_distributor","type":"address"},{"internalType":"bool","name":"_useBoost","type":"bool"}],"name":"addReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"address","name":"_distributor","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"approveRewardDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"balanceAtEpochOf","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint112","name":"locked","type":"uint112"},{"internalType":"uint112","name":"boosted","type":"uint112"},{"internalType":"uint32","name":"nextUnlockIndex","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostPayment","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"boostedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpointEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"claimableRewards","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct PopLocker.EarnedData[]","name":"userRewards","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"denominator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochs","outputs":[{"internalType":"uint224","name":"supply","type":"uint224"},{"internalType":"uint32","name":"date","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escrowDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_time","type":"uint256"}],"name":"findEpochId","outputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"getRewardForDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isShutdown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"kickExpiredLocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"kickRewardEpochDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kickRewardPerEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"lastTimeRewardApplicable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_spendRatio","type":"uint256"}],"name":"lock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"lockedBalanceOf","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"lockedBalances","outputs":[{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"unlockable","type":"uint256"},{"internalType":"uint256","name":"locked","type":"uint256"},{"components":[{"internalType":"uint112","name":"amount","type":"uint112"},{"internalType":"uint112","name":"boosted","type":"uint112"},{"internalType":"uint32","name":"unlockTime","type":"uint32"}],"internalType":"struct PopLocker.LockedBalance[]","name":"lockData","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumBoostPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextBoostRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextMaximumBoostPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"},{"internalType":"uint256","name":"_reward","type":"uint256"}],"name":"notifyRewardAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_relock","type":"bool"}],"name":"processExpiredLocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_relock","type":"bool"},{"internalType":"uint256","name":"_spendRatio","type":"uint256"},{"internalType":"address","name":"_withdrawTo","type":"address"}],"name":"processExpiredLocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardData","outputs":[{"internalType":"bool","name":"useBoost","type":"bool"},{"internalType":"uint40","name":"periodFinish","type":"uint40"},{"internalType":"uint208","name":"rewardRate","type":"uint208"},{"internalType":"uint40","name":"lastUpdateTime","type":"uint40"},{"internalType":"uint208","name":"rewardPerTokenStored","type":"uint208"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"rewardDistributors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsToken","type":"address"}],"name":"rewardPerToken","outputs":[{"internalType":"uint256","name":"","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":"address","name":"_user","type":"address"}],"name":"rewardWeightOf","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"rewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardsEscrow","outputs":[{"internalType":"contract IRewardsEscrow","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"setApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_max","type":"uint256"},{"internalType":"uint256","name":"_rate","type":"uint256"},{"internalType":"address","name":"_receivingAddress","type":"address"}],"name":"setBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"name":"setEscrowDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rate","type":"uint256"},{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setKickIncentive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewardsEscrow","type":"address"}],"name":"setRewardsEscrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"totalSupplyAtEpoch","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userLocks","outputs":[{"internalType":"uint112","name":"amount","type":"uint112"},{"internalType":"uint112","name":"boosted","type":"uint112"},{"internalType":"uint32","name":"unlockTime","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userRewardPerTokenPaid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a0604052600060108190556127106011819055601291909155601355606460145560046015556016805460ff191690553480156200003d57600080fd5b506040516200477438038062004774833981016040819052620000609162000350565b600160009081556200007162000233565b600180546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506040805180820190915260158082527f566f7465204c6f636b656420504f5020546f6b656e000000000000000000000060209092019182526200010591601791620002b4565b50604080518082019091526005808252640766c504f560dc1b60209092019182526200013491601891620002b4565b50600960f91b608052600280546001600160a01b03199081166001600160a01b0385811691909117909255600380549091169183169190911790556301e133806006556000620001ad62093a8062000199428262000237602090811b620021e017901c565b6200027860201b620022121790919060201c565b60408051808201909152600080825263ffffffff92831660208301908152600c8054600181018255925291517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790910180549251909316600160e01b026001600160e01b039182166001600160e01b031990931692909217161790555062000415915050565b3390565b6000808211620002645760405162461bcd60e51b81526004016200025b906200038e565b60405180910390fd5b8183816200026e57fe5b0490505b92915050565b600081158062000295575050808202828282816200029257fe5b04145b620002725760405162461bcd60e51b81526004016200025b90620003c5565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620002f757805160ff191683800117855562000327565b8280016001018555821562000327579182015b82811115620003275782518255916020019190600101906200030a565b506200033592915062000339565b5090565b5b808211156200033557600081556001016200033a565b6000806040838503121562000363578182fd5b82516200037081620003fc565b60208401519092506200038381620003fc565b809150509250929050565b6020808252601c908201527f426f72696e674d6174683a206469766973696f6e206279207a65726f00000000604082015260600190565b60208082526018908201527f426f72696e674d6174683a204d756c204f766572666c6f770000000000000000604082015260600190565b6001600160a01b03811681146200041257600080fd5b50565b60805160f81c6143416200043360003980610c9652506143416000f3fe608060405234801561001057600080fd5b50600436106103995760003560e01c80638757b15b116101e9578063c00007b01161010f578063e432488d116100ad578063f21579321161007c578063f215793214610742578063f2fde38b1461074a578063f82615971461075d578063fc0e74d11461077057610399565b8063e432488d14610701578063e465fe8014610709578063e70b9e271461071c578063f12297771461072f57610399565b8063ca5c7b91116100e9578063ca5c7b91146106b3578063d3c45c76146106bb578063dc01f60d146106ce578063e2ab691d146106ee57610399565b8063c00007b014610677578063c1009f4b1461068a578063c6b61e4c1461069257610399565b8063a81653c911610187578063b5ed7a6611610156578063b5ed7a6614610641578063b66503cf14610649578063bcd110141461065c578063bf86d6901461066f57610399565b8063a81653c91461060b578063a98e05bb1461061e578063aa33fedb14610626578063b187bc221461063957610399565b80638da5cb5b116101c35780638da5cb5b146105eb57806395d89b41146105f357806396ce0795146105fb5780639bdc74671461060357610399565b80638757b15b146105bd578063887c7dc5146105c55780638980f11f146105d857610399565b806357c2c2ba116102ce57806370b36d791161026c57806375aadf611161023b57806375aadf61146105925780637bb7bed11461059a5780637bd48c7c146105ad578063829965cc146105b557610399565b806370b36d791461054f57806370e664cd14610562578063715018a61461057557806372f702f31461057d57610399565b806363f1c8e2116102a857806363f1c8e2146105035780636724c910146105165780637035ab981461052957806370a082311461053c57610399565b806357c2c2ba146104d557806359355736146104dd578063638634ee146104f057610399565b80632fe871081161033b578063321bc34711610315578063321bc34714610476578063386a95251461048957806339fc97131461049157806348e5d9f8146104b157610399565b80632fe8710814610439578063312ff8391461044c578063313ce5671461046157610399565b806318160ddd1161037757806318160ddd146103f45780631c607395146103fc57806327e235e31461040f5780632e9564e41461043157610399565b8063045544431461039e5780630483a7f6146103bc57806306fdde03146103df575b600080fd5b6103a6610778565b6040516103b391906141f3565b60405180910390f35b6103cf6103ca3660046137d9565b61077f565b6040516103b39493929190614229565b6103e7610945565b6040516103b39190613b27565b6103a66109db565b6103a661040a366004613975565b610ab1565b61042261041d3660046137d9565b610bdd565b6040516103b3939291906141ab565b6103a6610c13565b6103a66104473660046137d9565b610c19565b61045f61045a3660046138cf565b610c48565b005b610469610c94565b6040516103b391906142ab565b61045f610484366004613945565b610cb8565b6103a6610d37565b6104a461049f3660046137f4565b610d3e565b6040516103b39190613ae6565b6104c46104bf3660046137d9565b610d5e565b6040516103b3959493929190613af1565b6103a6610daf565b6103a66104eb3660046137d9565b610db5565b6103a66104fe3660046137d9565b610dd9565b61045f610511366004613998565b610e07565b61045f610524366004613828565b610e94565b6103a66105373660046137f4565b610f4c565b6103a661054a3660046137d9565b610f69565b6103a661055d366004613945565b61108d565b61045f610570366004613907565b6111af565b61045f6111f3565b61058561127c565b6040516103b39190613a02565b6103a661128b565b6105856105a8366004613945565b611291565b6103a66112b8565b6103a66112be565b61045f6112c4565b61045f6105d33660046137d9565b611303565b61045f6105e6366004613872565b611354565b61058561145a565b6103e7611469565b6103a66114ca565b6103a66114d0565b61045f6106193660046139b9565b6114d6565b6105856115a7565b610422610634366004613872565b6115b6565b6103a6611602565b6103a6611608565b61045f610657366004613872565b61160e565b6103a661066a3660046137d9565b6118aa565b6104a46118e3565b61045f6106853660046137d9565b6118ec565b61045f611c4e565b6106a56106a0366004613945565b611c56565b6040516103b39291906141d4565b6103a6611c8b565b61045f6106c9366004613828565b611c91565b6106e16106dc3660046137d9565b611db6565b6040516103b39190613a8e565b61045f6106fc36600461389c565b611ef7565b6103a6611f42565b61045f6107173660046137d9565b611f48565b6103a661072a3660046137f4565b611ff0565b6103a661073d3660046137d9565b61200d565b610585612018565b61045f6107583660046137d9565b612027565b6103a661076b366004613945565b6120e8565b61045f612192565b626ebe0081565b6001600160a01b0381166000908152600e60209081526040808320600d9092528220805483928392606092600160e01b900463ffffffff1684815b845481101561092d57428582815481106107d057fe5b600091825260209091200154600160e01b900463ffffffff1611156108f7578161084d57845481900367ffffffffffffffff8111801561080f57600080fd5b5060405190808252806020026020018201604052801561084957816020015b61083661378b565b81526020019060019003908161082e5790505b5095505b84818154811061085957fe5b60009182526020918290206040805160608101825291909201546001600160701b038082168352600160701b8204169382019390935263ffffffff600160e01b909304929092169082015286518790849081106108b257fe5b602002602001018190525081806001019250506108f08582815481106108d457fe5b60009182526020909120015488906001600160701b0316612249565b9650610925565b61092285828154811061090657fe5b60009182526020909120015489906001600160701b0316612249565b97505b6001016107ba565b505090546001600160701b0316955050509193509193565b60178054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109d15780601f106109a6576101008083540402835291602001916109d1565b820191906000526020600020905b8154815290600101906020018083116109b457829003601f168201915b5050505050905090565b6000806109f562093a806109ef42826121e0565b90612212565b90506000610a0682626ebe0061226c565b600c805491925083906000198301838110610a1d57fe5b600091825260209091200154600160e01b900463ffffffff161415610a4157600019015b60001981015b6001810115610aaa576000600c8281548110610a5f57fe5b60009182526020909120018054909150600160e01b900463ffffffff168410610a885750610aaa565b8054610a9e9087906001600160e01b0316612249565b95505060001901610a47565b5050505090565b6001600160a01b0381166000908152600e60205260408120600c805483919086908110610ada57fe5b600091825260208220015463ffffffff600160e01b90910481169250610b07908390626ebe009061226c16565b90506000610b1c62093a806109ef42826121e0565b8454909150600019015b6001810115610bd1576000610b6a62093a80600c02878481548110610b4757fe5b60009182526020909120015463ffffffff600160e01b9091048116919061226c16565b9050848111158015610b7b57508281105b15610bc75783811115610bc157610bba868381548110610b9757fe5b6000918252602090912001548890600160701b90046001600160701b0316612249565b9650610bc7565b50610bd1565b5060001901610b26565b50505050505b92915050565b600d602052600090815260409020546001600160701b0380821691600160701b810490911690600160e01b900463ffffffff1683565b60115481565b6001600160a01b0381166000908152600d6020526040902054600160701b90046001600160701b03165b919050565b60026000541415610c745760405162461bcd60e51b8152600401610c6b90614095565b60405180910390fd5b6002600081905550610c8c338260003333600061228f565b506001600055565b7f000000000000000000000000000000000000000000000000000000000000000090565b610cc061284e565b6001600160a01b0316610cd161145a565b6001600160a01b031614610cf75760405162461bcd60e51b8152600401610c6b90613e82565b7f21c46a061cb9c101660f51f5c9fc9768c5f6e8cf5dea8ca5cd03cb6db13956f360065482604051610d2a92919061421b565b60405180910390a1600655565b62093a8081565b600760209081526000928352604080842090915290825290205460ff1681565b6005602052600090815260409020805460019091015460ff82169164ffffffffff61010082048116926001600160d01b03660100000000000090930483169291811691650100000000009091041685565b60065481565b6001600160a01b03166000908152600d60205260409020546001600160701b031690565b6001600160a01b038116600090815260056020526040812054610bd790610100900464ffffffffff16612852565b610e0f61284e565b6001600160a01b0316610e2061145a565b6001600160a01b031614610e465760405162461bcd60e51b8152600401610c6b90613e82565b6101f4821115610e685760405162461bcd60e51b8152600401610c6b90613d01565b6002811015610e895760405162461bcd60e51b8152600401610c6b90613f25565b601491909155601555565b610e9c61284e565b6001600160a01b0316610ead61145a565b6001600160a01b031614610ed35760405162461bcd60e51b8152600401610c6b90613e82565b6001600160a01b03831660009081526005602052604090206001015464ffffffffff16610f125760405162461bcd60e51b8152600401610c6b90613eb7565b6001600160a01b03928316600090815260076020908152604080832094909516825292909252919020805460ff1916911515919091179055565b600860209081526000928352604080842090915290825290205481565b6001600160a01b0381166000908152600e60209081526040808320600d90925290912080548254600160701b82046001600160701b0316939291600160e01b900463ffffffff1690815b8181101561102c5742858281548110610fc857fe5b600091825260209091200154600160e01b900463ffffffff161161101f57611018858281548110610ff557fe5b6000918252602090912001548790600160701b90046001600160701b031661226c565b9550611024565b61102c565b600101610fb3565b50600061104062093a806109ef42826121e0565b905060008211801561106957508061106762093a80600c02876001860381548110610b4757fe5b145b1561108357611080856001840381548110610ff557fe5b95505b5050505050919050565b6000806110ce62093a806109ef62093a80600c87815481106110ab57fe5b60009182526020909120015463ffffffff600160e01b909104811691906121e016565b905060006110df82626ebe0061226c565b905060006110f462093a806109ef42826121e0565b905080600c868154811061110457fe5b600091825260209091200154600160e01b900463ffffffff16141561112b57600019909401935b845b60018101156111a6576000600c828154811061114557fe5b60009182526020909120018054909150600160e01b900463ffffffff16841061116e57506111a6565b61119a600c838154811061117e57fe5b60009182526020909120015487906001600160e01b0316612249565b9550506000190161112d565b50505050919050565b600260005414156111d25760405162461bcd60e51b8152600401610c6b90614095565b60026000819055506111e93384848433600061228f565b5050600160005550565b6111fb61284e565b6001600160a01b031661120c61145a565b6001600160a01b0316146112325760405162461bcd60e51b8152600401610c6b90613e82565b6001546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600180546001600160a01b0319169055565b6002546001600160a01b031681565b600b5481565b6004818154811061129e57fe5b6000918252602090912001546001600160a01b0316905081565b60125481565b600c5490565b6003546002546112e2916001600160a01b039182169116600061285e565b600354600254611301916001600160a01b03918216911660001961285e565b565b600260005414156113265760405162461bcd60e51b8152600401610c6b90614095565b6002600081905550610c8c81600080843361134f60155462093a8061221290919063ffffffff16565b61228f565b61135c61284e565b6001600160a01b031661136d61145a565b6001600160a01b0316146113935760405162461bcd60e51b8152600401610c6b90613e82565b6002546001600160a01b03838116911614156113c15760405162461bcd60e51b8152600401610c6b90613eee565b6001600160a01b03821660009081526005602052604090206001015464ffffffffff16156114015760405162461bcd60e51b8152600401610c6b9061405e565b61141d61140c61145a565b6001600160a01b038416908361298e565b7f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa28828260405161144e929190613a54565b60405180910390a15050565b6001546001600160a01b031690565b60188054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156109d15780601f106109a6576101008083540402835291602001916109d1565b61271081565b60145481565b6114de61284e565b6001600160a01b03166114ef61145a565b6001600160a01b0316146115155760405162461bcd60e51b8152600401610c6b90613e82565b6105dc83106115365760405162461bcd60e51b8152600401610c6b90613cca565b61753082106115575760405162461bcd60e51b8152600401610c6b90613d01565b6001600160a01b03811661157d5760405162461bcd60e51b8152600401610c6b90613d6f565b601292909255601355600f80546001600160a01b0319166001600160a01b03909216919091179055565b600f546001600160a01b031681565b600e60205281600052604060002081815481106115cf57fe5b6000918252602090912001546001600160701b038082169350600160701b8204169150600160e01b900463ffffffff1683565b60105481565b60135481565b6000808052600d6020527f81955a0a11e65eac625c29e8882660bae4e165a75d72780094acae8ece9a29ee8054600160701b90046001600160701b0316825b6004548110156117df5760006004828154811061166657fe5b6000918252602090912001546001600160a01b0316905061168e611689826129ad565b612ac3565b6001600160a01b03821660009081526005602052604090206001810180546001600160d01b0393909316650100000000000265010000000000600160f81b031990931692909217909155546116f8906116f39064ffffffffff61010090910416612852565b612af0565b6001600160a01b038281166000908152600560205260409020600101805464ffffffffff191664ffffffffff93909316929092179091558516156117d6576001600160a01b038116600090815260056020526040902054611775908690839060ff1661176e5786546001600160701b0316611770565b855b612b17565b6001600160a01b0386811660008181526009602090815260408083209487168084529482528083209590955560058152848220600101549282526008815284822093825292909252919020650100000000009091046001600160d01b031690555b5060010161164d565b5050506001600160a01b038316600090815260076020908152604080832033845290915290205460ff166118255760405162461bcd60e51b8152600401610c6b90613e4b565b600082116118455760405162461bcd60e51b8152600401610c6b90613e14565b61184f8383612b8f565b6118646001600160a01b038416333085612ccb565b826001600160a01b03167fac24935fd910bc682b5ccb1a07b718cadf8cf2f6d1404c4f3ddc3662dae40e298360405161189d91906141f3565b60405180910390a2505050565b6001600160a01b038116600090815260056020526040812054610bd790660100000000000090046001600160d01b031662093a80612212565b60165460ff1681565b6002600054141561190f5760405162461bcd60e51b8152600401610c6b90614095565b600260009081556001600160a01b0382168152600d6020526040812080548392600160701b9091046001600160701b0316905b600454811015611ac35760006004828154811061195b57fe5b6000918252602090912001546001600160a01b0316905061197e611689826129ad565b6001600160a01b03821660009081526005602052604090206001810180546001600160d01b0393909316650100000000000265010000000000600160f81b031990931692909217909155546119e3906116f39064ffffffffff61010090910416612852565b6001600160a01b038281166000908152600560205260409020600101805464ffffffffff191664ffffffffff9390931692909217909155851615611aba576001600160a01b038116600090815260056020526040902054611a59908690839060ff1661176e5786546001600160701b0316611770565b6001600160a01b0386811660008181526009602090815260408083209487168084529482528083209590955560058152848220600101549282526008815284822093825292909252919020650100000000009091046001600160d01b031690555b50600101611942565b50505060005b6004548110156111e957600060048281548110611ae257fe5b60009182526020808320909101546001600160a01b038781168452600983526040808520919092168085529252909120549091508015611c44576001600160a01b0380861660009081526009602090815260408083209386168352929052908120819055611b5182600a6121e0565b90506000611b60826009612212565b9050611b766001600160a01b038516888461298e565b6003546006546040517fe2ab691d0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163e2ab691d91611bc4918b918691600401613a6d565b600060405180830381600087803b158015611bde57600080fd5b505af1158015611bf2573d6000803e3d6000fd5b50505050836001600160a01b0316876001600160a01b03167f540798df468d7b23d11f156fdb954cb19ad414d150722a7b6d55ba369dea792e85604051611c3991906141f3565b60405180910390a350505b5050600101611ac9565b611301612cf2565b600c8181548110611c6357fe5b6000918252602090912001546001600160e01b0381169150600160e01b900463ffffffff1682565b600a5481565b611c9961284e565b6001600160a01b0316611caa61145a565b6001600160a01b031614611cd05760405162461bcd60e51b8152600401610c6b90613e82565b6001600160a01b03831660009081526005602052604090206001015464ffffffffff1615611cfd57600080fd5b6004805460018082019092557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b0180546001600160a01b0319166001600160a01b039586169081179091556000908152600560209081526040808320808501805464ffffffffff19164264ffffffffff16908117909155815465ffffffffff0019166101009091021760ff1990811696151596909617905560078252808320959096168252939093529290912080549091169091179055565b60045460609067ffffffffffffffff81118015611dd257600080fd5b50604051908082528060200260200182016040528015611e0c57816020015b611df96137ab565b815260200190600190039081611df15790505b506001600160a01b0383166000908152600d60205260408120805492935091600160701b90046001600160701b0316905b8351811015611eef57600060048281548110611e5557fe5b9060005260206000200160009054906101000a90046001600160a01b0316905080858381518110611e8257fe5b6020908102919091018101516001600160a01b039283169052908216600090815260059091526040902054611ecc908790839060ff1661176e5786546001600160701b0316611770565b858381518110611ed857fe5b602090810291909101810151015250600101611e3d565b505050919050565b60026000541415611f1a5760405162461bcd60e51b8152600401610c6b90614095565b6002600081905554611f37906001600160a01b0316333085612ccb565b6111e9838383612e72565b60155481565b611f5061284e565b6001600160a01b0316611f6161145a565b6001600160a01b031614611f875760405162461bcd60e51b8152600401610c6b90613e82565b6003546040517fee4ec82b92f0e1fe230e6604a4752fa407a28069f106dc41e53edc28c4bc504e91611fc6916001600160a01b03909116908490613a16565b60405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b600960209081526000928352604080842090915290825290205481565b6000610bd7826129ad565b6003546001600160a01b031681565b61202f61284e565b6001600160a01b031661204061145a565b6001600160a01b0316146120665760405162461bcd60e51b8152600401610c6b90613e82565b6001600160a01b03811661208c5760405162461bcd60e51b8152600401610c6b90613bff565b6001546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3600180546001600160a01b0319166001600160a01b0392909216919091179055565b600c54600090600019018161210462093a806109ef86826121e0565b935060005b608081101561218a5782821061211e5761218a565b600060026001848601010490506000600c828154811061213a57fe5b600091825260209091200154600160e01b900463ffffffff1690508681141561216957509350610c4392505050565b8681101561217957819350612180565b6001820394505b5050600101612109565b509392505050565b61219a61284e565b6001600160a01b03166121ab61145a565b6001600160a01b0316146121d15760405162461bcd60e51b8152600401610c6b90613e82565b6016805460ff19166001179055565b60008082116122015760405162461bcd60e51b8152600401610c6b90613bc8565b81838161220a57fe5b049392505050565b600081158061222d5750508082028282828161222a57fe5b04145b610bd75760405162461bcd60e51b8152600401610c6b90614129565b81810181811015610bd75760405162461bcd60e51b8152600401610c6b90613da6565b80820382811115610bd75760405162461bcd60e51b8152600401610c6b90613b5a565b6001600160a01b0386166000908152600d6020526040812080548892600160701b9091046001600160701b0316905b60045481101561243f576000600482815481106122d757fe5b6000918252602090912001546001600160a01b031690506122fa611689826129ad565b6001600160a01b03821660009081526005602052604090206001810180546001600160d01b0393909316650100000000000265010000000000600160f81b0319909316929092179091555461235f906116f39064ffffffffff61010090910416612852565b6001600160a01b038281166000908152600560205260409020600101805464ffffffffff191664ffffffffff9390931692909217909155851615612436576001600160a01b0381166000908152600560205260409020546123d5908690839060ff1661176e5786546001600160701b0316611770565b6001600160a01b0386811660008181526009602090815260408083209487168084529482528083209590955560058152848220600101549282526008815284822093825292909252919020650100000000009091046001600160d01b031690555b506001016122be565b5050506001600160a01b0387166000908152600e60209081526040808320600d9092528220815460165492939192829190829060ff16806124b05750612485428961226c565b86600184038154811061249457fe5b600091825260209091200154600160e01b900463ffffffff1611155b156125275784546001600160701b038082169550600160701b9091041692506124d88261348b565b855463ffffffff91909116600160e01b026001600160e01b0390911617855587156125225761251f8887600185038154811061251057fe5b906000526020600020016134b1565b90505b61262e565b8454600160e01b900463ffffffff16805b8381101561260e5761254a428b61226c565b88828154811061255657fe5b600091825260209091200154600160e01b900463ffffffff16111561257a5761260e565b6125a788828154811061258957fe5b6000918252602090912001546001600160701b038881169116613547565b95506125dd8882815481106125b857fe5b6000918252602090912001546001600160701b0387811691600160701b900416613547565b94508915612602576125ff6125f88b8a848154811061251057fe5b8490612249565b92505b60019182019101612538565b50855463ffffffff909116600160e01b026001600160e01b039091161785555b6000846001600160701b0316116126575760405162461bcd60e51b8152600401610c6b90613d38565b845461266c906001600160701b031685613576565b85546dffffffffffffffffffffffffffff19166001600160701b03918216178087556126a191600160701b9091041684613576565b85546dffffffffffffffffffffffffffff60701b1916600160701b6001600160701b0392831602178655600a546126d991861661226c565b600a55600b546126f2906001600160701b03851661226c565b600b55801561277d57612717612707826135a5565b6001600160701b03861690613576565b600254909450612731906001600160a01b03168a8361298e565b8c6001600160a01b0316896001600160a01b03167f7e7ff29ed04cfb223bc9b02606f69520517c117ee82c9158ed2d96323c1ef3858360405161277491906141f3565b60405180910390a35b8b156127dd576127978a856001600160701b03168d612e72565b8c6001600160a01b03167fe2d155d9d74decc198a9a9b4f5bddb24ee0842ee745c9ce57e3573b971e50d9d856040516127d09190614197565b60405180910390a261283f565b6002546127fd906001600160a01b03168b6001600160701b03871661298e565b8c6001600160a01b03167f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5856040516128369190614197565b60405180910390a25b50505050505050505050505050565b3390565b6000610bd742836135ce565b8015806128ff57506040517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b0384169063dd62ed3e906128ad9030908690600401613a16565b60206040518083038186803b1580156128c557600080fd5b505afa1580156128d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128fd919061395d565b155b61291b5760405162461bcd60e51b8152600401610c6b906140cc565b6129898363095ea7b360e01b848460405160240161293a929190613a54565b60408051601f198184030181529190526020810180516001600160e01b03167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526135e4565b505050565b6129898363a9059cbb60e01b848460405160240161293a929190613a54565b6000600b54600014156129ee57506001600160a01b0381166000908152600560205260409020600101546501000000000090046001600160d01b0316610c43565b6001600160a01b038216600090815260056020526040902054610bd790612a8f9060ff16612a1e57600a54612a22565b600b545b6001600160a01b03851660009081526005602052604090208054600190910154612a8991670de0b6b3a7640000916109ef916001600160d01b03660100000000000082041691839164ffffffffff91821691612a8391610100900416612852565b9061226c565b906121e0565b6001600160a01b0384166000908152600560205260409020600101546501000000000090046001600160d01b031690612249565b60006001600160d01b03821115612aec5760405162461bcd60e51b8152600401610c6b90613b91565b5090565b600064ffffffffff821115612aec5760405162461bcd60e51b8152600401610c6b90614160565b6001600160a01b038084166000818152600960209081526040808320948716808452948252808320549383526008825280832094835293905291822054612b859190612b7f90670de0b6b3a764000090612a8990612b7890612a838a6129ad565b8790612212565b90612249565b90505b9392505050565b6001600160a01b03821660009081526005602052604090208054610100900464ffffffffff164210612bf457612bcb6116898362093a806121e0565b81546001600160d01b039190911666010000000000000265ffffffffffff909116178155612c72565b8054600090612c0f90610100900464ffffffffff164261226c565b8254909150600090612c35908390660100000000000090046001600160d01b0316612212565b9050612c4b61168962093a80612a898785612249565b83546001600160d01b039190911666010000000000000265ffffffffffff90911617835550505b612c7b42612af0565b60018201805464ffffffffff191664ffffffffff92909216919091179055612ca96116f34262093a80612249565b815464ffffffffff919091166101000265ffffffffff00199091161790555050565b612cec846323b872dd60e01b85858560405160240161293a93929190613a30565b50505050565b6000612d0562093a806109ef42826121e0565b600c805491925082906000198301838110612d1c57fe5b600091825260209091200154600160e01b900463ffffffff161015612e6e575b600c80548391906000198101908110612d5157fe5b600091825260209091200154600160e01b900463ffffffff1614612e4a576000612db062093a80600c6001600c805490500381548110612d8d57fe5b60009182526020909120015463ffffffff600160e01b9091048116919061224916565b60408051808201909152600080825263ffffffff92831660208301908152600c8054600181018255925291517fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790910180549251909316600160e01b026001600160e01b039182167fffffffff00000000000000000000000000000000000000000000000000000000909316929092171617905550612d3c565b60135460115414612e5c576013546011555b60125460105414612e6e576012546010555b5050565b6001600160a01b0383166000908152600d6020526040812080548592600160701b9091046001600160701b0316905b60045481101561302257600060048281548110612eba57fe5b6000918252602090912001546001600160a01b03169050612edd611689826129ad565b6001600160a01b03821660009081526005602052604090206001810180546001600160d01b0393909316650100000000000265010000000000600160f81b03199093169290921790915554612f42906116f39064ffffffffff61010090910416612852565b6001600160a01b038281166000908152600560205260409020600101805464ffffffffff191664ffffffffff9390931692909217909155851615613019576001600160a01b038116600090815260056020526040902054612fb8908690839060ff1661176e5786546001600160701b0316611770565b6001600160a01b0386811660008181526009602090815260408083209487168084529482528083209590955560058152848220600101549282526008815284822093825292909252919020650100000000009091046001600160d01b031690555b50600101612ea1565b505050600083116130455760405162461bcd60e51b8152600401610c6b90613c5c565b6010548211156130675760405162461bcd60e51b8152600401610c6b90613c93565b60165460ff161561308a5760405162461bcd60e51b8152600401610c6b90613f5c565b6001600160a01b0384166000908152600d602052604090206130aa612cf2565b60006130bc612710612a898787612212565b905060006130e56010546000146130d5576010546130d8565b60015b601154612a899088612212565b905060006130fb6130f6888561226c565b6135a5565b9050600061311c6130f6613115612710612a898c88612212565b8a90612249565b8554909150613134906001600160701b031683613547565b85546dffffffffffffffffffffffffffff19166001600160701b039182161780875561316991600160701b9091041682613547565b85546dffffffffffffffffffffffffffff60701b1916600160701b6001600160701b0392831602178655600a546131a1918416612249565b600a55600b546131ba906001600160701b038316612249565b600b5560006131d062093a806109ef42826121e0565b905060006131e182626ebe00612249565b6001600160a01b038c166000908152600e602052604090205490915080158061324b57506001600160a01b038c166000908152600e602052604090208054839190600019840190811061323057fe5b600091825260209091200154600160e01b900463ffffffff16105b15613308576001600160a01b038c166000908152600e6020908152604080832081516060810183526001600160701b03808b16825289811682860190815263ffffffff808a16958401958652845460018101865594885295909620915191909201805495519351909416600160e01b026001600160e01b03938316600160701b026dffffffffffffffffffffffffffff60701b19929093166dffffffffffffffffffffffffffff19909616959095171617169190911790556133b6565b6001600160a01b038c166000908152600e602052604081208054600019840190811061333057fe5b60009182526020909120018054909150613353906001600160701b031687613547565b81546dffffffffffffffffffffffffffff19166001600160701b039182161780835561338891600160701b9091041686613547565b81546001600160701b0391909116600160701b026dffffffffffffffffffffffffffff60701b199091161790555b600c80546000919060001981019081106133cc57fe5b600091825260209091200180549091506133f8906001600160e01b03166001600160701b038716613673565b81547fffffffff00000000000000000000000000000000000000000000000000000000166001600160e01b0391909116178155871561344e57600f5460025461344e916001600160a01b0391821691168a61298e565b8c6001600160a01b03167fb4caaf29adda3eefee3ad552a8e85058589bf834c7466cae4ee58787f70589ed8d8888604051612836939291906141fc565b600063ffffffff821115612aec5760405162461bcd60e51b8152600401610c6b90613fca565b6000806134c962093a806109ef81612a89428961226c565b83549091506000906134f69062093a8090612a8990859063ffffffff600160e01b90910481169061226c16565b9050600061351d6135158360010160145461221290919063ffffffff16565b6127106135ce565b855490915061353d9061271090612a89906001600160701b031684612212565b9695505050505050565b8181016001600160701b038083169082161015610bd75760405162461bcd60e51b8152600401610c6b90613da6565b8082036001600160701b038084169082161115610bd75760405162461bcd60e51b8152600401610c6b90613b5a565b60006001600160701b03821115612aec5760405162461bcd60e51b8152600401610c6b90613ddd565b60008183106135dd5781612b88565b5090919050565b6060613639826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166136a29092919063ffffffff16565b805190915015612989578080602001905181019061365791906138eb565b6129895760405162461bcd60e51b8152600401610c6b90614001565b8181016001600160e01b038083169082161015610bd75760405162461bcd60e51b8152600401610c6b90613da6565b6060612b858484600085856136b68561374c565b6136d25760405162461bcd60e51b8152600401610c6b90613f93565b60006060866001600160a01b031685876040516136ef91906139e6565b60006040518083038185875af1925050503d806000811461372c576040519150601f19603f3d011682016040523d82523d6000602084013e613731565b606091505b5091509150613741828286613752565b979650505050505050565b3b151590565b60608315613761575081612b88565b8251156137715782518084602001fd5b8160405162461bcd60e51b8152600401610c6b9190613b27565b604080516060810182526000808252602082018190529181019190915290565b604080518082019091526000808252602082015290565b80356001600160a01b0381168114610bd757600080fd5b6000602082840312156137ea578081fd5b612b8883836137c2565b60008060408385031215613806578081fd5b61381084846137c2565b915061381f84602085016137c2565b90509250929050565b60008060006060848603121561383c578081fd5b8335613847816142e5565b92506020840135613857816142e5565b91506040840135613867816142fd565b809150509250925092565b60008060408385031215613884578182fd5b61388e84846137c2565b946020939093013593505050565b6000806000606084860312156138b0578283fd5b6138ba85856137c2565b95602085013595506040909401359392505050565b6000602082840312156138e0578081fd5b8135612b88816142fd565b6000602082840312156138fc578081fd5b8151612b88816142fd565b60008060006060848603121561391b578283fd5b8335613926816142fd565b92506020840135915061393c85604086016137c2565b90509250925092565b600060208284031215613956578081fd5b5035919050565b60006020828403121561396e578081fd5b5051919050565b60008060408385031215613987578182fd5b8235915061381f84602085016137c2565b600080604083850312156139aa578182fd5b50508035926020909101359150565b6000806000606084860312156139cd578283fd5b83359250602084013591506040840135613867816142e5565b600082516139f88184602087016142b9565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039390931683526020830191909152604082015260600190565b602080825282518282018190526000919060409081850190868401855b82811015613ad957815180516001600160a01b03168552860151868501529284019290850190600101613aab565b5091979650505050505050565b901515815260200190565b941515855264ffffffffff93841660208601526001600160d01b0392831660408601529216606084015216608082015260a00190565b6000602082528251806020840152613b468160408501602087016142b9565b601f01601f19169190910160400192915050565b60208082526015908201527f426f72696e674d6174683a20556e646572666c6f770000000000000000000000604082015260600190565b6020808252601c908201527f426f72696e674d6174683a2075696e74323038204f766572666c6f7700000000604082015260600190565b6020808252601c908201527f426f72696e674d6174683a206469766973696f6e206279207a65726f00000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201527f6464726573730000000000000000000000000000000000000000000000000000606082015260800190565b6020808252600e908201527f43616e6e6f74207374616b652030000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f6f766572206d6178207370656e64000000000000000000000000000000000000604082015260600190565b60208082526010908201527f6f766572206d6178207061796d656e7400000000000000000000000000000000604082015260600190565b6020808252600d908201527f6f766572206d6178207261746500000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f6e6f20657870206c6f636b730000000000000000000000000000000000000000604082015260600190565b6020808252600f908201527f696e76616c696420616464726573730000000000000000000000000000000000604082015260600190565b60208082526018908201527f426f72696e674d6174683a20416464204f766572666c6f770000000000000000604082015260600190565b6020808252601c908201527f426f72696e674d6174683a2075696e74313132204f766572666c6f7700000000604082015260600190565b60208082526009908201527f4e6f207265776172640000000000000000000000000000000000000000000000604082015260600190565b6020808252600e908201527f6e6f7420617574686f72697a6564000000000000000000000000000000000000604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601c908201527f7265776172647320746f6b656e20646f6573206e6f7420657869737400000000604082015260600190565b6020808252601d908201527f43616e6e6f74207769746864726177207374616b696e6720746f6b656e000000604082015260600190565b60208082526009908201527f6d696e2064656c61790000000000000000000000000000000000000000000000604082015260600190565b60208082526008908201527f73687574646f776e000000000000000000000000000000000000000000000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252601b908201527f426f72696e674d6174683a2075696e743332204f766572666c6f770000000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60408201527f6f74207375636365656400000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f43616e6e6f742077697468647261772072657761726420746f6b656e00000000604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b60208082526018908201527f426f72696e674d6174683a204d756c204f766572666c6f770000000000000000604082015260600190565b6020808252601b908201527f426f72696e674d6174683a2075696e743430204f766572666c6f770000000000604082015260600190565b6001600160701b0391909116815260200190565b6001600160701b03938416815291909216602082015263ffffffff909116604082015260600190565b6001600160e01b0392909216825263ffffffff16602082015260400190565b90815260200190565b9283526001600160701b03918216602084015216604082015260600190565b918252602082015260400190565b6000608082018683526020868185015260408681860152606060808187015283875180865260a0880191508489019550865b8181101561429a57865180516001600160701b03908116855287820151168785015285015163ffffffff1685840152958501959183019160010161425b565b50909b9a5050505050505050505050565b60ff91909116815260200190565b60005b838110156142d45781810151838201526020016142bc565b83811115612cec5750506000910152565b6001600160a01b03811681146142fa57600080fd5b50565b80151581146142fa57600080fdfea2646970667358221220cb30992a7b73c34e46d3f4b71f3de5796cf7a441bca4c67abbd34c76f71504b664736f6c634300060c0033000000000000000000000000c5b57e9a1e7914fda753a88f24e5703e617ee50c000000000000000000000000a82caa79f35f7d6b6f1ec1971878f3474c894565
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c5b57e9a1e7914fda753a88f24e5703e617ee50c000000000000000000000000a82caa79f35f7d6b6f1ec1971878f3474c894565
-----Decoded View---------------
Arg [0] : _stakingToken (address): 0xc5b57e9a1e7914fda753a88f24e5703e617ee50c
Arg [1] : _rewardsEscrow (address): 0xa82caa79f35f7d6b6f1ec1971878f3474c894565
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c5b57e9a1e7914fda753a88f24e5703e617ee50c
Arg [1] : 000000000000000000000000a82caa79f35f7d6b6f1ec1971878f3474c894565
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.