Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- BribeFactory
- Optimization enabled
- true
- Compiler version
- v0.8.13+commit.abaa5c0e
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2022-09-16T14:45:49.883011Z
Contract source code
// File: contracts/interfaces/IGauge.sol pragma solidity 0.8.13; interface IGauge { function notifyRewardAmount(address token, uint amount) external; function getReward(address account, address[] memory tokens) external; function claimFees() external returns (uint claimed0, uint claimed1); function left(address token) external view returns (uint); function isForPair() external view returns (bool); } // File: contracts/interfaces/IVotingEscrow.sol pragma solidity 0.8.13; interface IVotingEscrow { struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } function token() external view returns (address); function team() external returns (address); function epoch() external view returns (uint); function point_history(uint loc) external view returns (Point memory); function user_point_history(uint tokenId, uint loc) external view returns (Point memory); function user_point_epoch(uint tokenId) external view returns (uint); function ownerOf(uint) external view returns (address); function isApprovedOrOwner(address, uint) external view returns (bool); function transferFrom(address, address, uint) external; function voting(uint tokenId) external; function abstain(uint tokenId) external; function attach(uint tokenId) external; function detach(uint tokenId) external; function checkpoint() external; function deposit_for(uint tokenId, uint value) external; function create_lock_for(uint, uint, address) external returns (uint); function balanceOfNFT(uint) external view returns (uint); function totalSupply() external view returns (uint); } // File: contracts/interfaces/IVoter.sol pragma solidity 0.8.13; interface IVoter { function _ve() external view returns (address); function governor() external view returns (address); function emergencyCouncil() external view returns (address); function attachTokenToGauge(uint _tokenId, address account) external; function detachTokenFromGauge(uint _tokenId, address account) external; function emitDeposit(uint _tokenId, address account, uint amount) external; function emitWithdraw(uint _tokenId, address account, uint amount) external; function isWhitelisted(address token) external view returns (bool); function notifyRewardAmount(uint amount) external; function distribute(address _gauge) external; } // File: contracts/interfaces/IERC20.sol pragma solidity 0.8.13; interface IERC20 { function totalSupply() external view returns (uint256); function transfer(address recipient, uint amount) external returns (bool); function decimals() external view returns (uint8); function symbol() external view returns (string memory); function balanceOf(address) external view returns (uint); function transferFrom(address sender, address recipient, uint amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); event Transfer(address indexed from, address indexed to, uint value); event Approval(address indexed owner, address indexed spender, uint value); } // File: contracts/interfaces/IBribe.sol pragma solidity 0.8.13; interface IBribe { function _deposit(uint amount, uint tokenId) external; function _withdraw(uint amount, uint tokenId) external; function getRewardForOwner(uint tokenId, address[] memory tokens) external; function notifyRewardAmount(address token, uint amount) external; function left(address token) external view returns (uint); } // File: contracts/libraries/Math.sol pragma solidity 0.8.13; library Math { function max(uint a, uint b) internal pure returns (uint) { return a >= b ? a : b; } function min(uint a, uint b) internal pure returns (uint) { return a < b ? a : b; } function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } function cbrt(uint256 n) internal pure returns (uint256) { unchecked { uint256 x = 0; for (uint256 y = 1 << 255; y > 0; y >>= 3) { x <<= 1; uint256 z = 3 * x * (x + 1) + 1; if (n / y >= z) { n -= y * z; x += 1; } } return x; }} } // File: contracts/ExternalBribe.sol pragma solidity 0.8.13; // Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote()) contract ExternalBribe is IBribe { address public immutable voter; // only voter can modify balances (since it only happens on vote()) address public immutable _ve; // 天使のたまご uint internal constant DURATION = 7 days; // rewards are released over the voting period uint internal constant MAX_REWARD_TOKENS = 16; uint internal constant PRECISION = 10 ** 18; uint public totalSupply; mapping(uint => uint) public balanceOf; mapping(address => mapping(uint => uint)) public tokenRewardsPerEpoch; mapping(address => uint) public periodFinish; mapping(address => mapping(uint => uint)) public lastEarn; address[] public rewards; mapping(address => bool) public isReward; /// @notice A checkpoint for marking balance struct Checkpoint { uint timestamp; uint balanceOf; } /// @notice A checkpoint for marking supply struct SupplyCheckpoint { uint timestamp; uint supply; } /// @notice A record of balance checkpoints for each account, by index mapping (uint => mapping (uint => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping (uint => uint) public numCheckpoints; /// @notice A record of balance checkpoints for each token, by index mapping (uint => SupplyCheckpoint) public supplyCheckpoints; /// @notice The number of checkpoints uint public supplyNumCheckpoints; event Deposit(address indexed from, uint tokenId, uint amount); event Withdraw(address indexed from, uint tokenId, uint amount); event NotifyReward(address indexed from, address indexed reward, uint epoch, uint amount); event ClaimRewards(address indexed from, address indexed reward, uint amount); constructor(address _voter, address[] memory _allowedRewardTokens) { voter = _voter; _ve = IVoter(_voter)._ve(); for (uint i; i < _allowedRewardTokens.length; i++) { if (_allowedRewardTokens[i] != address(0)) { isReward[_allowedRewardTokens[i]] = true; rewards.push(_allowedRewardTokens[i]); } } } // simple re-entrancy check uint internal _unlocked = 1; modifier lock() { require(_unlocked == 1); _unlocked = 2; _; _unlocked = 1; } function _bribeStart(uint timestamp) internal pure returns (uint) { return timestamp - (timestamp % (7 days)); } function getEpochStart(uint timestamp) public pure returns (uint) { uint bribeStart = _bribeStart(timestamp); uint bribeEnd = bribeStart + DURATION; return timestamp < bribeEnd ? bribeStart : bribeStart + 7 days; } /** * @notice Determine the prior balance for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param tokenId The token of the NFT to check * @param timestamp The timestamp to get the balance at * @return The balance the account had as of the given block */ function getPriorBalanceIndex(uint tokenId, uint timestamp) public view returns (uint) { uint nCheckpoints = numCheckpoints[tokenId]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[tokenId][nCheckpoints - 1].timestamp <= timestamp) { return (nCheckpoints - 1); } // Next check implicit zero balance if (checkpoints[tokenId][0].timestamp > timestamp) { return 0; } uint lower = 0; uint upper = nCheckpoints - 1; while (upper > lower) { uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[tokenId][center]; if (cp.timestamp == timestamp) { return center; } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return lower; } function getPriorSupplyIndex(uint timestamp) public view returns (uint) { uint nCheckpoints = supplyNumCheckpoints; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (supplyCheckpoints[nCheckpoints - 1].timestamp <= timestamp) { return (nCheckpoints - 1); } // Next check implicit zero balance if (supplyCheckpoints[0].timestamp > timestamp) { return 0; } uint lower = 0; uint upper = nCheckpoints - 1; while (upper > lower) { uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow SupplyCheckpoint memory cp = supplyCheckpoints[center]; if (cp.timestamp == timestamp) { return center; } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return lower; } function _writeCheckpoint(uint tokenId, uint balance) internal { uint _timestamp = block.timestamp; uint _nCheckPoints = numCheckpoints[tokenId]; if (_nCheckPoints > 0 && checkpoints[tokenId][_nCheckPoints - 1].timestamp == _timestamp) { checkpoints[tokenId][_nCheckPoints - 1].balanceOf = balance; } else { checkpoints[tokenId][_nCheckPoints] = Checkpoint(_timestamp, balance); numCheckpoints[tokenId] = _nCheckPoints + 1; } } function _writeSupplyCheckpoint() internal { uint _nCheckPoints = supplyNumCheckpoints; uint _timestamp = block.timestamp; if (_nCheckPoints > 0 && supplyCheckpoints[_nCheckPoints - 1].timestamp == _timestamp) { supplyCheckpoints[_nCheckPoints - 1].supply = totalSupply; } else { supplyCheckpoints[_nCheckPoints] = SupplyCheckpoint(_timestamp, totalSupply); supplyNumCheckpoints = _nCheckPoints + 1; } } function rewardsListLength() external view returns (uint) { return rewards.length; } // returns the last time the reward was modified or periodFinish if the reward has ended function lastTimeRewardApplicable(address token) public view returns (uint) { return Math.min(block.timestamp, periodFinish[token]); } // allows a user to claim rewards for a given token function getReward(uint tokenId, address[] memory tokens) external lock { require(IVotingEscrow(_ve).isApprovedOrOwner(msg.sender, tokenId)); for (uint i = 0; i < tokens.length; i++) { uint _reward = earned(tokens[i], tokenId); lastEarn[tokens[i]][tokenId] = block.timestamp; if (_reward > 0) _safeTransfer(tokens[i], msg.sender, _reward); emit ClaimRewards(msg.sender, tokens[i], _reward); } } // used by Voter to allow batched reward claims function getRewardForOwner(uint tokenId, address[] memory tokens) external lock { require(msg.sender == voter); address _owner = IVotingEscrow(_ve).ownerOf(tokenId); for (uint i = 0; i < tokens.length; i++) { uint _reward = earned(tokens[i], tokenId); lastEarn[tokens[i]][tokenId] = block.timestamp; if (_reward > 0) _safeTransfer(tokens[i], _owner, _reward); emit ClaimRewards(_owner, tokens[i], _reward); } } function earned(address token, uint tokenId) public view returns (uint) { uint _startTimestamp = lastEarn[token][tokenId]; if (numCheckpoints[tokenId] == 0) { return 0; } uint _startIndex = getPriorBalanceIndex(tokenId, _startTimestamp); uint _endIndex = numCheckpoints[tokenId]-1; uint reward = 0; // you only earn once per epoch (after it's over) Checkpoint memory prevRewards; // reuse struct to avoid stack too deep prevRewards.timestamp = _bribeStart(_startTimestamp); uint _prevSupply = 1; if (_endIndex > 0) { for (uint i = _startIndex; i <= _endIndex - 1; i++) { Checkpoint memory cp0 = checkpoints[tokenId][i]; uint _nextEpochStart = _bribeStart(cp0.timestamp); // check that you've earned it // this won't happen until a week has passed if (_nextEpochStart > prevRewards.timestamp) { reward += prevRewards.balanceOf; } prevRewards.timestamp = _nextEpochStart; _prevSupply = supplyCheckpoints[getPriorSupplyIndex(_nextEpochStart + DURATION)].supply; prevRewards.balanceOf = cp0.balanceOf * tokenRewardsPerEpoch[token][_nextEpochStart] / _prevSupply; } } Checkpoint memory cp = checkpoints[tokenId][_endIndex]; uint _lastEpochStart = _bribeStart(cp.timestamp); uint _lastEpochEnd = _lastEpochStart + DURATION; if (block.timestamp > _lastEpochEnd) { reward += cp.balanceOf * tokenRewardsPerEpoch[token][_lastEpochStart] / supplyCheckpoints[getPriorSupplyIndex(_lastEpochEnd)].supply; } return reward; } // This is an external function, but internal notation is used since it can only be called "internally" from Gauges function _deposit(uint amount, uint tokenId) external { require(msg.sender == voter); totalSupply += amount; balanceOf[tokenId] += amount; _writeCheckpoint(tokenId, balanceOf[tokenId]); _writeSupplyCheckpoint(); emit Deposit(msg.sender, tokenId, amount); } function _withdraw(uint amount, uint tokenId) external { require(msg.sender == voter); totalSupply -= amount; balanceOf[tokenId] -= amount; _writeCheckpoint(tokenId, balanceOf[tokenId]); _writeSupplyCheckpoint(); emit Withdraw(msg.sender, tokenId, amount); } function left(address token) external view returns (uint) { uint adjustedTstamp = getEpochStart(block.timestamp); return tokenRewardsPerEpoch[token][adjustedTstamp]; } function notifyRewardAmount(address token, uint amount) external lock { require(amount > 0); if (!isReward[token]) { require(IVoter(voter).isWhitelisted(token), "bribe tokens must be whitelisted"); require(rewards.length < MAX_REWARD_TOKENS, "too many rewards tokens"); } // bribes kick in at the start of next bribe period uint adjustedTstamp = getEpochStart(block.timestamp); uint epochRewards = tokenRewardsPerEpoch[token][adjustedTstamp]; _safeTransferFrom(token, msg.sender, address(this), amount); tokenRewardsPerEpoch[token][adjustedTstamp] = epochRewards + amount; periodFinish[token] = adjustedTstamp + DURATION; if (!isReward[token]) { isReward[token] = true; rewards.push(token); } emit NotifyReward(msg.sender, token, adjustedTstamp, amount); } function swapOutRewardToken(uint i, address oldToken, address newToken) external { require(msg.sender == IVotingEscrow(_ve).team(), 'only team'); require(rewards[i] == oldToken); isReward[oldToken] = false; isReward[newToken] = true; rewards[i] = newToken; } function _safeTransfer(address token, address to, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } function _safeTransferFrom(address token, address from, address to, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } } // File: contracts/InternalBribe.sol pragma solidity 0.8.13; // Bribes pay out rewards for a given pool based on the votes that were received from the user (goes hand in hand with Voter.vote()) contract InternalBribe is IBribe { address public immutable voter; // only voter can modify balances (since it only happens on vote()) address public immutable _ve; uint public constant DURATION = 7 days; // rewards are released over 7 days uint public constant PRECISION = 10 ** 18; uint internal constant MAX_REWARD_TOKENS = 16; // default snx staking contract implementation mapping(address => uint) public rewardRate; mapping(address => uint) public periodFinish; mapping(address => uint) public lastUpdateTime; mapping(address => uint) public rewardPerTokenStored; mapping(address => mapping(uint => uint)) public lastEarn; mapping(address => mapping(uint => uint)) public userRewardPerTokenStored; address[] public rewards; mapping(address => bool) public isReward; uint public totalSupply; mapping(uint => uint) public balanceOf; /// @notice A checkpoint for marking balance struct Checkpoint { uint timestamp; uint balanceOf; } /// @notice A checkpoint for marking reward rate struct RewardPerTokenCheckpoint { uint timestamp; uint rewardPerToken; } /// @notice A checkpoint for marking supply struct SupplyCheckpoint { uint timestamp; uint supply; } /// @notice A record of balance checkpoints for each account, by index mapping (uint => mapping (uint => Checkpoint)) public checkpoints; /// @notice The number of checkpoints for each account mapping (uint => uint) public numCheckpoints; /// @notice A record of balance checkpoints for each token, by index mapping (uint => SupplyCheckpoint) public supplyCheckpoints; /// @notice The number of checkpoints uint public supplyNumCheckpoints; /// @notice A record of balance checkpoints for each token, by index mapping (address => mapping (uint => RewardPerTokenCheckpoint)) public rewardPerTokenCheckpoints; /// @notice The number of checkpoints for each token mapping (address => uint) public rewardPerTokenNumCheckpoints; event Deposit(address indexed from, uint tokenId, uint amount); event Withdraw(address indexed from, uint tokenId, uint amount); event NotifyReward(address indexed from, address indexed reward, uint amount); event ClaimRewards(address indexed from, address indexed reward, uint amount); constructor(address _voter, address[] memory _allowedRewardTokens) { voter = _voter; _ve = IVoter(_voter)._ve(); for (uint i; i < _allowedRewardTokens.length; i++) { if (_allowedRewardTokens[i] != address(0)) { isReward[_allowedRewardTokens[i]] = true; rewards.push(_allowedRewardTokens[i]); } } } // simple re-entrancy check uint internal _unlocked = 1; modifier lock() { require(_unlocked == 1); _unlocked = 2; _; _unlocked = 1; } /** * @notice Determine the prior balance for an account as of a block number * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. * @param tokenId The token of the NFT to check * @param timestamp The timestamp to get the balance at * @return The balance the account had as of the given block */ function getPriorBalanceIndex(uint tokenId, uint timestamp) public view returns (uint) { uint nCheckpoints = numCheckpoints[tokenId]; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (checkpoints[tokenId][nCheckpoints - 1].timestamp <= timestamp) { return (nCheckpoints - 1); } // Next check implicit zero balance if (checkpoints[tokenId][0].timestamp > timestamp) { return 0; } uint lower = 0; uint upper = nCheckpoints - 1; while (upper > lower) { uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow Checkpoint memory cp = checkpoints[tokenId][center]; if (cp.timestamp == timestamp) { return center; } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return lower; } function getPriorSupplyIndex(uint timestamp) public view returns (uint) { uint nCheckpoints = supplyNumCheckpoints; if (nCheckpoints == 0) { return 0; } // First check most recent balance if (supplyCheckpoints[nCheckpoints - 1].timestamp <= timestamp) { return (nCheckpoints - 1); } // Next check implicit zero balance if (supplyCheckpoints[0].timestamp > timestamp) { return 0; } uint lower = 0; uint upper = nCheckpoints - 1; while (upper > lower) { uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow SupplyCheckpoint memory cp = supplyCheckpoints[center]; if (cp.timestamp == timestamp) { return center; } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return lower; } function getPriorRewardPerToken(address token, uint timestamp) public view returns (uint, uint) { uint nCheckpoints = rewardPerTokenNumCheckpoints[token]; if (nCheckpoints == 0) { return (0,0); } // First check most recent balance if (rewardPerTokenCheckpoints[token][nCheckpoints - 1].timestamp <= timestamp) { return (rewardPerTokenCheckpoints[token][nCheckpoints - 1].rewardPerToken, rewardPerTokenCheckpoints[token][nCheckpoints - 1].timestamp); } // Next check implicit zero balance if (rewardPerTokenCheckpoints[token][0].timestamp > timestamp) { return (0,0); } uint lower = 0; uint upper = nCheckpoints - 1; while (upper > lower) { uint center = upper - (upper - lower) / 2; // ceil, avoiding overflow RewardPerTokenCheckpoint memory cp = rewardPerTokenCheckpoints[token][center]; if (cp.timestamp == timestamp) { return (cp.rewardPerToken, cp.timestamp); } else if (cp.timestamp < timestamp) { lower = center; } else { upper = center - 1; } } return (rewardPerTokenCheckpoints[token][lower].rewardPerToken, rewardPerTokenCheckpoints[token][lower].timestamp); } function _writeCheckpoint(uint tokenId, uint balance) internal { uint _timestamp = block.timestamp; uint _nCheckPoints = numCheckpoints[tokenId]; if (_nCheckPoints > 0 && checkpoints[tokenId][_nCheckPoints - 1].timestamp == _timestamp) { checkpoints[tokenId][_nCheckPoints - 1].balanceOf = balance; } else { checkpoints[tokenId][_nCheckPoints] = Checkpoint(_timestamp, balance); numCheckpoints[tokenId] = _nCheckPoints + 1; } } function _writeRewardPerTokenCheckpoint(address token, uint reward, uint timestamp) internal { uint _nCheckPoints = rewardPerTokenNumCheckpoints[token]; if (_nCheckPoints > 0 && rewardPerTokenCheckpoints[token][_nCheckPoints - 1].timestamp == timestamp) { rewardPerTokenCheckpoints[token][_nCheckPoints - 1].rewardPerToken = reward; } else { rewardPerTokenCheckpoints[token][_nCheckPoints] = RewardPerTokenCheckpoint(timestamp, reward); rewardPerTokenNumCheckpoints[token] = _nCheckPoints + 1; } } function _writeSupplyCheckpoint() internal { uint _nCheckPoints = supplyNumCheckpoints; uint _timestamp = block.timestamp; if (_nCheckPoints > 0 && supplyCheckpoints[_nCheckPoints - 1].timestamp == _timestamp) { supplyCheckpoints[_nCheckPoints - 1].supply = totalSupply; } else { supplyCheckpoints[_nCheckPoints] = SupplyCheckpoint(_timestamp, totalSupply); supplyNumCheckpoints = _nCheckPoints + 1; } } function rewardsListLength() external view returns (uint) { return rewards.length; } // returns the last time the reward was modified or periodFinish if the reward has ended function lastTimeRewardApplicable(address token) public view returns (uint) { return Math.min(block.timestamp, periodFinish[token]); } // allows a user to claim rewards for a given token function getReward(uint tokenId, address[] memory tokens) external lock { require(IVotingEscrow(_ve).isApprovedOrOwner(msg.sender, tokenId)); for (uint i = 0; i < tokens.length; i++) { (rewardPerTokenStored[tokens[i]], lastUpdateTime[tokens[i]]) = _updateRewardPerToken(tokens[i], type(uint).max, true); uint _reward = earned(tokens[i], tokenId); lastEarn[tokens[i]][tokenId] = block.timestamp; userRewardPerTokenStored[tokens[i]][tokenId] = rewardPerTokenStored[tokens[i]]; if (_reward > 0) _safeTransfer(tokens[i], msg.sender, _reward); emit ClaimRewards(msg.sender, tokens[i], _reward); } } // used by Voter to allow batched reward claims function getRewardForOwner(uint tokenId, address[] memory tokens) external lock { require(msg.sender == voter); address _owner = IVotingEscrow(_ve).ownerOf(tokenId); for (uint i = 0; i < tokens.length; i++) { (rewardPerTokenStored[tokens[i]], lastUpdateTime[tokens[i]]) = _updateRewardPerToken(tokens[i], type(uint).max, true); uint _reward = earned(tokens[i], tokenId); lastEarn[tokens[i]][tokenId] = block.timestamp; userRewardPerTokenStored[tokens[i]][tokenId] = rewardPerTokenStored[tokens[i]]; if (_reward > 0) _safeTransfer(tokens[i], _owner, _reward); emit ClaimRewards(_owner, tokens[i], _reward); } } function rewardPerToken(address token) public view returns (uint) { if (totalSupply == 0) { return rewardPerTokenStored[token]; } return rewardPerTokenStored[token] + ((lastTimeRewardApplicable(token) - Math.min(lastUpdateTime[token], periodFinish[token])) * rewardRate[token] * PRECISION / totalSupply); } function batchRewardPerToken(address token, uint maxRuns) external { (rewardPerTokenStored[token], lastUpdateTime[token]) = _batchRewardPerToken(token, maxRuns); } function _batchRewardPerToken(address token, uint maxRuns) internal returns (uint, uint) { uint _startTimestamp = lastUpdateTime[token]; uint reward = rewardPerTokenStored[token]; if (supplyNumCheckpoints == 0) { return (reward, _startTimestamp); } if (rewardRate[token] == 0) { return (reward, block.timestamp); } uint _startIndex = getPriorSupplyIndex(_startTimestamp); uint _endIndex = Math.min(supplyNumCheckpoints-1, maxRuns); for (uint i = _startIndex; i < _endIndex; i++) { SupplyCheckpoint memory sp0 = supplyCheckpoints[i]; if (sp0.supply > 0) { SupplyCheckpoint memory sp1 = supplyCheckpoints[i+1]; (uint _reward, uint endTime) = _calcRewardPerToken(token, sp1.timestamp, sp0.timestamp, sp0.supply, _startTimestamp); reward += _reward; _writeRewardPerTokenCheckpoint(token, reward, endTime); _startTimestamp = endTime; } } return (reward, _startTimestamp); } function _calcRewardPerToken(address token, uint timestamp1, uint timestamp0, uint supply, uint startTimestamp) internal view returns (uint, uint) { uint endTime = Math.max(timestamp1, startTimestamp); return (((Math.min(endTime, periodFinish[token]) - Math.min(Math.max(timestamp0, startTimestamp), periodFinish[token])) * rewardRate[token] * PRECISION / supply), endTime); } /// @dev Update stored rewardPerToken values without the last one snapshot /// If the contract will get "out of gas" error on users actions this will be helpful function batchUpdateRewardPerToken(address token, uint maxRuns) external { (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, maxRuns, false); } function _updateRewardForAllTokens() internal { uint length = rewards.length; for (uint i; i < length; i++) { address token = rewards[i]; (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true); } } function _updateRewardPerToken(address token, uint maxRuns, bool actualLast) internal returns (uint, uint) { uint _startTimestamp = lastUpdateTime[token]; uint reward = rewardPerTokenStored[token]; if (supplyNumCheckpoints == 0) { return (reward, _startTimestamp); } if (rewardRate[token] == 0) { return (reward, block.timestamp); } uint _startIndex = getPriorSupplyIndex(_startTimestamp); uint _endIndex = Math.min(supplyNumCheckpoints - 1, maxRuns); if (_endIndex > 0) { for (uint i = _startIndex; i <= _endIndex - 1; i++) { SupplyCheckpoint memory sp0 = supplyCheckpoints[i]; if (sp0.supply > 0) { SupplyCheckpoint memory sp1 = supplyCheckpoints[i+1]; (uint _reward, uint _endTime) = _calcRewardPerToken(token, sp1.timestamp, sp0.timestamp, sp0.supply, _startTimestamp); reward += _reward; _writeRewardPerTokenCheckpoint(token, reward, _endTime); _startTimestamp = _endTime; } } } if (actualLast) { SupplyCheckpoint memory sp = supplyCheckpoints[_endIndex]; if (sp.supply > 0) { (uint _reward,) = _calcRewardPerToken(token, lastTimeRewardApplicable(token), Math.max(sp.timestamp, _startTimestamp), sp.supply, _startTimestamp); reward += _reward; _writeRewardPerTokenCheckpoint(token, reward, block.timestamp); _startTimestamp = block.timestamp; } } return (reward, _startTimestamp); } function earned(address token, uint tokenId) public view returns (uint) { uint _startTimestamp = Math.max(lastEarn[token][tokenId], rewardPerTokenCheckpoints[token][0].timestamp); if (numCheckpoints[tokenId] == 0) { return 0; } uint _startIndex = getPriorBalanceIndex(tokenId, _startTimestamp); uint _endIndex = numCheckpoints[tokenId]-1; uint reward = 0; if (_endIndex > 0) { for (uint i = _startIndex; i <= _endIndex-1; i++) { Checkpoint memory cp0 = checkpoints[tokenId][i]; Checkpoint memory cp1 = checkpoints[tokenId][i+1]; (uint _rewardPerTokenStored0,) = getPriorRewardPerToken(token, cp0.timestamp); (uint _rewardPerTokenStored1,) = getPriorRewardPerToken(token, cp1.timestamp); reward += cp0.balanceOf * (_rewardPerTokenStored1 - _rewardPerTokenStored0) / PRECISION; } } Checkpoint memory cp = checkpoints[tokenId][_endIndex]; (uint _rewardPerTokenStored,) = getPriorRewardPerToken(token, cp.timestamp); reward += cp.balanceOf * (rewardPerToken(token) - Math.max(_rewardPerTokenStored, userRewardPerTokenStored[token][tokenId])) / PRECISION; return reward; } // This is an external function, but internal notation is used since it can only be called "internally" from Gauges function _deposit(uint amount, uint tokenId) external { require(msg.sender == voter, "not bribe voter"); _updateRewardForAllTokens(); totalSupply += amount; balanceOf[tokenId] += amount; _writeCheckpoint(tokenId, balanceOf[tokenId]); _writeSupplyCheckpoint(); emit Deposit(msg.sender, tokenId, amount); } function _withdraw(uint amount, uint tokenId) external { require(msg.sender == voter); _updateRewardForAllTokens(); totalSupply -= amount; balanceOf[tokenId] -= amount; _writeCheckpoint(tokenId, balanceOf[tokenId]); _writeSupplyCheckpoint(); emit Withdraw(msg.sender, tokenId, amount); } function left(address token) external view returns (uint) { if (block.timestamp >= periodFinish[token]) return 0; uint _remaining = periodFinish[token] - block.timestamp; return _remaining * rewardRate[token]; } // used to notify a gauge/bribe of a given reward, this can create griefing attacks by extending rewards function notifyRewardAmount(address token, uint amount) external lock { require(amount > 0); require(isReward[token]); if (rewardRate[token] == 0) _writeRewardPerTokenCheckpoint(token, 0, block.timestamp); (rewardPerTokenStored[token], lastUpdateTime[token]) = _updateRewardPerToken(token, type(uint).max, true); if (block.timestamp >= periodFinish[token]) { _safeTransferFrom(token, msg.sender, address(this), amount); rewardRate[token] = amount / DURATION; } else { uint _remaining = periodFinish[token] - block.timestamp; uint _left = _remaining * rewardRate[token]; require(amount > _left); _safeTransferFrom(token, msg.sender, address(this), amount); rewardRate[token] = (amount + _left) / DURATION; } require(rewardRate[token] > 0); uint balance = IERC20(token).balanceOf(address(this)); require(rewardRate[token] <= balance / DURATION, "Provided reward too high"); periodFinish[token] = block.timestamp + DURATION; emit NotifyReward(msg.sender, token, amount); } function swapOutRewardToken(uint i, address oldToken, address newToken) external { require(msg.sender == IVotingEscrow(_ve).team(), 'only team'); require(rewards[i] == oldToken); isReward[oldToken] = false; isReward[newToken] = true; rewards[i] = newToken; } function _safeTransfer(address token, address to, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } function _safeTransferFrom(address token, address from, address to, uint256 value) internal { require(token.code.length > 0); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool)))); } } // File: contracts/interfaces/IBribeFactory.sol pragma solidity 0.8.13; interface IBribeFactory { function createInternalBribe(address[] memory) external returns (address); function createExternalBribe(address[] memory) external returns (address); } // File: contracts/factories/BribeFactory.sol pragma solidity 0.8.13; contract BribeFactory is IBribeFactory { address public last_internal_bribe; address public last_external_bribe; function createInternalBribe(address[] memory allowedRewards) external returns (address) { last_internal_bribe = address(new InternalBribe(msg.sender, allowedRewards)); return last_internal_bribe; } function createExternalBribe(address[] memory allowedRewards) external returns (address) { last_external_bribe = address(new ExternalBribe(msg.sender, allowedRewards)); return last_external_bribe; } }
Contract ABI
[{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"createExternalBribe","inputs":[{"type":"address[]","name":"allowedRewards","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"createInternalBribe","inputs":[{"type":"address[]","name":"allowedRewards","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"last_external_bribe","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"last_internal_bribe","inputs":[]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50614cff806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80632a26b9eb146100515780636485f0c414610080578063b0ad856f14610093578063eb57738c146100a6575b600080fd5b61006461005f3660046101bf565b6100b9565b6040516001600160a01b03909116815260200160405180910390f35b61006461008e3660046101bf565b610116565b600154610064906001600160a01b031681565b600054610064906001600160a01b031681565b600033826040516100c990610173565b6100d4929190610284565b604051809103906000f0801580156100f0573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b0392909216918217905592915050565b6000338260405161012690610180565b610131929190610284565b604051809103906000f08015801561014d573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b0392909216918217905592915050565b612b66806102e183390190565b611e8380612e4783390190565b634e487b7160e01b600052604160045260246000fd5b80356001600160a01b03811681146101ba57600080fd5b919050565b600060208083850312156101d257600080fd5b823567ffffffffffffffff808211156101ea57600080fd5b818501915085601f8301126101fe57600080fd5b8135818111156102105761021061018d565b8060051b604051601f19603f830116810181811085821117156102355761023561018d565b60405291825284820192508381018501918883111561025357600080fd5b938501935b8285101561027857610269856101a3565b84529385019392850192610258565b98975050505050505050565b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b818110156102d25785518516835294830194918301916001016102b4565b50909897505050505050505056fe60c060405260016010553480156200001657600080fd5b5060405162002b6638038062002b668339810160408190526200003991620001f8565b6001600160a01b038216608081905260408051638dd598fb60e01b81529051638dd598fb916004808201926020929091908290030181865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa9190620002e1565b6001600160a01b031660a05260005b8151811015620001bc5760006001600160a01b0316828281518110620000e357620000e362000306565b60200260200101516001600160a01b031614620001a75760016007600084848151811062000115576200011562000306565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555060068282815181106200016b576200016b62000306565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b80620001b3816200031c565b915050620000b9565b50505062000344565b80516001600160a01b0381168114620001dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200020c57600080fd5b6200021783620001c5565b602084810151919350906001600160401b03808211156200023757600080fd5b818601915086601f8301126200024c57600080fd5b815181811115620002615762000261620001e2565b8060051b604051601f19603f83011681018181108582111715620002895762000289620001e2565b604052918252848201925083810185019189831115620002a857600080fd5b938501935b82851015620002d157620002c185620001c5565b84529385019392850192620002ad565b8096505050505050509250929050565b600060208284031215620002f457600080fd5b620002ff82620001c5565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200033d57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a0516127d2620003946000396000818161042301528181610a0201528181610e82015261167801526000818161031101528181610c0d01528181610e3f015261154d01526127d26000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c80639cc7f70811610125578063e6886396116100ad578063f301af421161007c578063f301af4214610595578063f3207723146105a8578063f5f8d365146105bb578063f7412baf146105ce578063fd314098146105f557600080fd5b8063e688639614610546578063e8111a121461054e578063f122977714610557578063f25e55a51461056a57600080fd5b8063a7852afa116100f4578063a7852afa146104d1578063aa479652146104e4578063aaf5eb6814610504578063b66503cf14610513578063da09d19d1461052657600080fd5b80639cc7f7081461046b5780639ce43f901461048b5780639e2bf22c146104ab578063a28d4c9c146104be57600080fd5b80634d5ce038116101a857806368fcee1a1161017757806368fcee1a146103f857806376f4be361461040b5780638dd598fb1461041e5780639418f9391461044557806399bcc0521461045857600080fd5b80634d5ce0381461037d57806350589793146103b05780635a45d052146103d0578063638634ee146103e557600080fd5b80632ce9aead116101ef5780632ce9aead146102ae5780633b881999146102ce5780633e491d47146102f957806346c96aac1461030c57806349dcc2041461034b57600080fd5b806301316ddf1461022157806318160ddd1461026d5780631be0528914610284578063221ca18c1461028e575b600080fd5b61025361022f3660046124a7565b600e6020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152015b60405180910390f35b61027660085481565b604051908152602001610264565b61027662093a8081565b61027661029c3660046124d3565b60006020819052908152604090205481565b6102766102bc3660046124d3565b60026020526000908152604090205481565b6102766102dc3660046124a7565b600560209081526000928352604080842090915290825290205481565b6102766103073660046124a7565b610608565b6103337f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610264565b6102536103593660046124f0565b600a6020908152600092835260408084209091529082529020805460019091015482565b6103a061038b3660046124d3565b60076020526000908152604090205460ff1681565b6040519015158152602001610264565b6102766103be366004612512565b600b6020526000908152604090205481565b6103e36103de3660046124a7565b610864565b005b6102766103f33660046124d3565b61089c565b6103e36104063660046124a7565b6108c0565b610276610419366004612512565b6108cc565b6103337f000000000000000000000000000000000000000000000000000000000000000081565b6103e361045336600461252b565b610a00565b6102766104663660046124d3565b610b91565b610276610479366004612512565b60096020526000908152604090205481565b6102766104993660046124d3565b60036020526000908152604090205481565b6103e36104b93660046124f0565b610c02565b6102766104cc3660046124f0565b610cdb565b6103e36104df366004612583565b610e20565b6102766104f23660046124d3565b600f6020526000908152604090205481565b610276670de0b6b3a764000081565b6103e36105213660046124a7565b611165565b6102766105343660046124d3565b60016020526000908152604090205481565b600654610276565b610276600d5481565b6102766105653660046124d3565b61145b565b6102766105783660046124a7565b600460209081526000928352604080842090915290825290205481565b6103336105a3366004612512565b611518565b6103e36105b63660046124f0565b611542565b6103e36105c9366004612583565b611648565b6102536105dc366004612512565b600c602052600090815260409020805460019091015482565b6102536106033660046124a7565b61194f565b6001600160a01b0382166000818152600460209081526040808320858452825280832054938352600e82528083208380529091528120549091829161064d9190611b70565b6000848152600b60205260408120549192500361066e57600091505061085e565b600061067a8483610cdb565b6000858152600b6020526040812054919250906106999060019061266a565b9050600081156107a257825b6106b060018461266a565b81116107a0576000878152600a60208181526040808420858552808352818520825180840190935280548352600190810154838501528c865293909252929182906106fc908690612681565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600061073b8b846000015161194f565b509050600061074e8c846000015161194f565b509050670de0b6b3a7640000610764838361266a565b85602001516107739190612699565b61077d91906126b8565b6107879087612681565b9550505050508080610798906126da565b9150506106a5565b505b6000868152600a602090815260408083208584528252808320815180830190925280548083526001909101549282019290925291906107e2908a9061194f565b506001600160a01b038a1660009081526005602090815260408083208c8452909152902054909150670de0b6b3a76400009061081f908390611b70565b6108288b61145b565b610832919061266a565b83602001516108419190612699565b61084b91906126b8565b6108559084612681565b96505050505050505b92915050565b61086e8282611b87565b6001600160a01b03909316600090815260036020908152604080832060029092529091209390935590915550565b6001600160a01b03811660009081526001602052604081205461085e904290611cea565b61086e82826000611cf9565b600d546000908082036108e25750600092915050565b82600c60006108f260018561266a565b8152602001908152602001600020600001541161091b5761091460018261266a565b9392505050565b60008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e8548310156109565750600092915050565b60008061096460018461266a565b90505b818111156109f8576000600261097d848461266a565b61098791906126b8565b610991908361266a565b6000818152600c60209081526040918290208251808401909352805480845260019091015491830191909152919250908790036109d2575095945050505050565b80518711156109e3578193506109f1565b6109ee60018361266a565b92505b5050610967565b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166385f2aef26040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8491906126f3565b6001600160a01b0316336001600160a01b031614610ad55760405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b60448201526064015b60405180910390fd5b816001600160a01b031660068481548110610af257610af2612710565b6000918252602090912001546001600160a01b031614610b1157600080fd5b6001600160a01b03808316600090815260076020526040808220805460ff1990811690915592841682529020805490911660011790556006805482919085908110610b5e57610b5e612710565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b6001600160a01b0381166000908152600160205260408120544210610bb857506000919050565b6001600160a01b038216600090815260016020526040812054610bdc90429061266a565b6001600160a01b0384166000908152602081905260409020549091506109149082612699565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c3757600080fd5b610c3f611ee9565b8160086000828254610c51919061266a565b909155505060008181526009602052604081208054849290610c7490849061266a565b9091555050600081815260096020526040902054610c93908290611f71565b610c9b61204a565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56891015b60405180910390a25050565b6000828152600b6020526040812054808203610cfb57600091505061085e565b6000848152600a602052604081208491610d1660018561266a565b81526020019081526020016000206000015411610d4057610d3860018261266a565b91505061085e565b6000848152600a60209081526040808320838052909152902054831015610d6b57600091505061085e565b600080610d7960018461266a565b90505b81811115610e175760006002610d92848461266a565b610d9c91906126b8565b610da6908361266a565b6000888152600a60209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090879003610df15750935061085e92505050565b8051871115610e0257819350610e10565b610e0d60018361266a565b92505b5050610d7c565b50949350505050565b601054600114610e2f57600080fd5b6002601055336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e6957600080fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef591906126f3565b905060005b825181101561115a57610f2a838281518110610f1857610f18612710565b60200260200101516000196001611cf9565b60036000868581518110610f4057610f40612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060026000888781518110610f8057610f80612710565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008491905055839190505550506000610fdb848381518110610fcd57610fcd612710565b602002602001015186610608565b90504260046000868581518110610ff457610ff4612710565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000878152602001908152602001600020819055506003600085848151811061104757611047612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546005600086858151811061108657611086612710565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812089825290925290205580156110e1576110e18483815181106110d2576110d2612710565b602002602001015184836120ee565b8382815181106110f3576110f3612710565b60200260200101516001600160a01b0316836001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc98360405161113f91815260200190565b60405180910390a35080611152816126da565b915050610efa565b505060016010555050565b60105460011461117457600080fd5b60026010558061118357600080fd5b6001600160a01b03821660009081526007602052604090205460ff166111a857600080fd5b6001600160a01b03821660009081526020819052604081205490036111d3576111d3826000426121dd565b6111e1826000196001611cf9565b6001600160a01b038416600090815260036020908152604080832060028352818420949094559390925560019091522054421061124f57611224823330846122cc565b61123162093a80826126b8565b6001600160a01b0383166000908152602081905260409020556112e8565b6001600160a01b03821660009081526001602052604081205461127390429061266a565b6001600160a01b0384166000908152602081905260408120549192509061129a9083612699565b90508083116112a857600080fd5b6112b4843330866122cc565b62093a806112c28285612681565b6112cc91906126b8565b6001600160a01b03851660009081526020819052604090205550505b6001600160a01b03821660009081526020819052604090205461130a57600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015611351573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113759190612726565b905061138462093a80826126b8565b6001600160a01b03841660009081526020819052604090205411156113eb5760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606401610acc565b6113f862093a8042612681565b6001600160a01b0384166000818152600160205260409081902092909255905133907ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf50826906114499086815260200190565b60405180910390a35050600160105550565b600060085460000361148357506001600160a01b031660009081526003602052604090205490565b6008546001600160a01b0383166000908152602081815260408083205460028352818420546001909352922054670de0b6b3a764000092916114c491611cea565b6114cd8661089c565b6114d7919061266a565b6114e19190612699565b6114eb9190612699565b6114f591906126b8565b6001600160a01b03831660009081526003602052604090205461085e9190612681565b6006818154811061152857600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115ac5760405162461bcd60e51b815260206004820152600f60248201526e3737ba10313934b132903b37ba32b960891b6044820152606401610acc565b6115b4611ee9565b81600860008282546115c69190612681565b9091555050600081815260096020526040812080548492906115e9908490612681565b9091555050600081815260096020526040902054611608908290611f71565b61161061204a565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159101610ccf565b60105460011461165757600080fd5b600260105560405163430c208160e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c208190604401602060405180830381865afa1580156116c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116eb919061273f565b6116f457600080fd5b60005b815181101561194557611715828281518110610f1857610f18612710565b6003600085858151811061172b5761172b612710565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006002600087878151811061176b5761176b612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600084919050558391905055505060006117c68383815181106117b8576117b8612710565b602002602001015185610608565b905042600460008585815181106117df576117df612710565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000868152602001908152602001600020819055506003600084848151811061183257611832612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546005600085858151811061187157611871612710565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812088825290925290205580156118cc576118cc8383815181106118bd576118bd612710565b602002602001015133836120ee565b8282815181106118de576118de612710565b60200260200101516001600160a01b0316336001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc98360405161192a91815260200190565b60405180910390a3508061193d816126da565b9150506116f7565b5050600160105550565b6001600160a01b0382166000908152600f6020526040812054819080820361197e576000809250925050611b69565b6001600160a01b0385166000908152600e6020526040812085916119a360018561266a565b81526020019081526020016000206000015411611a40576001600160a01b0385166000908152600e60205260408120906119de60018461266a565b815260200190815260200160002060010154600e6000876001600160a01b03166001600160a01b031681526020019081526020016000206000600184611a24919061266a565b8152602001908152602001600020600001549250925050611b69565b6001600160a01b0385166000908152600e60209081526040808320838052909152902054841015611a78576000809250925050611b69565b600080611a8660018461266a565b90505b81811115611b385760006002611a9f848461266a565b611aa991906126b8565b611ab3908361266a565b6001600160a01b0389166000908152600e60209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090889003611b1257602081015190519096509450611b699350505050565b8051881115611b2357819350611b31565b611b2e60018361266a565b92505b5050611a89565b506001600160a01b0386166000908152600e6020908152604080832093835292905220600181015490549093509150505b9250929050565b600081831015611b805781610914565b5090919050565b6001600160a01b0382166000908152600260209081526040808320546003909252822054600d54839291908303611bc15792509050611b69565b6001600160a01b0386166000908152602081905260408120549003611bec579250429150611b699050565b6000611bf7836108cc565b90506000611c136001600d54611c0d919061266a565b88611cea565b9050815b81811015611cdb576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611cc8576000600c81611c5c856001612681565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600080611ca78d8460000151866000015187602001518d6123c4565b9092509050611cb68289612681565b9750611cc38d89836121dd565b975050505b5080611cd3816126da565b915050611c17565b50919792965091945050505050565b6000818310611b805781610914565b6001600160a01b0383166000908152600260209081526040808320546003909252822054600d54839291908303611d335792509050611ee1565b6001600160a01b0387166000908152602081905260408120549003611d5e579250429150611ee19050565b6000611d69836108cc565b90506000611d856001600d54611d7f919061266a565b89611cea565b90508015611e5e57815b611d9a60018361266a565b8111611e5c576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611e49576000600c81611ddd856001612681565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600080611e288e8460000151866000015187602001518d6123c4565b9092509050611e378289612681565b9750611e448e89836121dd565b975050505b5080611e54816126da565b915050611d8f565b505b8615611ed8576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611ed6576000611eb78b611ea08d61089c565b8451611eac908a611b70565b85602001518a6123c4565b509050611ec48186612681565b9450611ed18b86426121dd565b429550505b505b50909350909150505b935093915050565b60065460005b81811015611f6d57600060068281548110611f0c57611f0c612710565b6000918252602090912001546001600160a01b03169050611f31816000196001611cf9565b6001600160a01b039092166000908152600360209081526040808320600290925290912092909255905580611f65816126da565b915050611eef565b5050565b6000828152600b602052604090205442908015801590611fbb57506000848152600a602052604081208391611fa760018561266a565b815260200190815260200160002060000154145b15611ff4576000848152600a602052604081208491611fdb60018561266a565b8152602081019190915260400160002060010155612044565b60408051808201825283815260208082018681526000888152600a8352848120868252909252929020905181559051600191820155612034908290612681565b6000858152600b60205260409020555b50505050565b600d5442811580159061207c575080600c600061206860018661266a565b815260200190815260200160002060000154145b156120ab57600854600c600061209360018661266a565b81526020810191909152604001600020600101555050565b60408051808201825282815260085460208083019182526000868152600c909152929092209051815590516001918201556120e7908390612681565b600d555050565b6000836001600160a01b03163b1161210557600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916121619190612761565b6000604051808303816000865af19150503d806000811461219e576040519150601f19603f3d011682016040523d82523d6000602084013e6121a3565b606091505b50915091508180156121cd5750805115806121cd5750808060200190518101906121cd919061273f565b6121d657600080fd5b5050505050565b6001600160a01b0383166000908152600f6020526040902054801580159061223957506001600160a01b0384166000908152600e60205260408120839161222560018561266a565b815260200190815260200160002060000154145b15612263576001600160a01b0384166000908152600e602052604081208491611fdb60018561266a565b60408051808201825283815260208082018681526001600160a01b0388166000908152600e83528481208682529092529290209051815590516001918201556122ad908290612681565b6001600160a01b0385166000908152600f602052604090205550505050565b6000846001600160a01b03163b116122e357600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916123479190612761565b6000604051808303816000865af19150503d8060008114612384576040519150601f19603f3d011682016040523d82523d6000602084013e612389565b606091505b50915091508180156123b35750805115806123b35750808060200190518101906123b3919061273f565b6123bc57600080fd5b505050505050565b60008060006123d38785611b70565b6001600160a01b0389166000908152602081905260409020549091508590670de0b6b3a7640000906124266124088a89611b70565b6001600160a01b038d16600090815260016020526040902054611cea565b6001600160a01b038c1660009081526001602052604090205461244a908690611cea565b612454919061266a565b61245e9190612699565b6124689190612699565b61247291906126b8565b9890975095505050505050565b6001600160a01b038116811461249457600080fd5b50565b80356124a28161247f565b919050565b600080604083850312156124ba57600080fd5b82356124c58161247f565b946020939093013593505050565b6000602082840312156124e557600080fd5b81356109148161247f565b6000806040838503121561250357600080fd5b50508035926020909101359150565b60006020828403121561252457600080fd5b5035919050565b60008060006060848603121561254057600080fd5b8335925060208401356125528161247f565b915060408401356125628161247f565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561259657600080fd5b8235915060208084013567ffffffffffffffff808211156125b657600080fd5b818601915086601f8301126125ca57600080fd5b8135818111156125dc576125dc61256d565b8060051b604051601f19603f830116810181811085821117156126015761260161256d565b60405291825284820192508381018501918983111561261f57600080fd5b938501935b828510156126445761263585612497565b84529385019392850192612624565b8096505050505050509250929050565b634e487b7160e01b600052601160045260246000fd5b60008282101561267c5761267c612654565b500390565b6000821982111561269457612694612654565b500190565b60008160001904831182151516156126b3576126b3612654565b500290565b6000826126d557634e487b7160e01b600052601260045260246000fd5b500490565b6000600182016126ec576126ec612654565b5060010190565b60006020828403121561270557600080fd5b81516109148161247f565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561273857600080fd5b5051919050565b60006020828403121561275157600080fd5b8151801515811461091457600080fd5b6000825160005b818110156127825760208186018101518583015201612768565b81811115612791576000828501525b50919091019291505056fea2646970667358221220edc839d72bbcddae86ef704bcf28c42aed623358aa6831ada7e5f16192a1458064736f6c634300080d003360c06040526001600b553480156200001657600080fd5b5060405162001e8338038062001e838339810160408190526200003991620001f8565b6001600160a01b038216608081905260408051638dd598fb60e01b81529051638dd598fb916004808201926020929091908290030181865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa9190620002e1565b6001600160a01b031660a05260005b8151811015620001bc5760006001600160a01b0316828281518110620000e357620000e362000306565b60200260200101516001600160a01b031614620001a75760016006600084848151811062000115576200011562000306565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555060058282815181106200016b576200016b62000306565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b80620001b3816200031c565b915050620000b9565b50505062000344565b80516001600160a01b0381168114620001dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200020c57600080fd5b6200021783620001c5565b602084810151919350906001600160401b03808211156200023757600080fd5b818601915086601f8301126200024c57600080fd5b815181811115620002615762000261620001e2565b8060051b604051601f19603f83011681018181108582111715620002895762000289620001e2565b604052918252848201925083810185019189831115620002a857600080fd5b938501935b82851015620002d157620002c185620001c5565b84529385019392850192620002ad565b8096505050505050509250929050565b600060208284031215620002f457600080fd5b620002ff82620001c5565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200033d57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a051611ae86200039b600039600081816102d90152818161089b01528181610cda015261125c0152600081816101da01528181610a6e01528181610c9701528181610ed5015261116f0152611ae86000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80639cc7f708116100de578063e688639611610097578063f301af4211610071578063f301af4214610416578063f320772314610429578063f5f8d3651461043c578063f7412baf1461044f57600080fd5b8063e6886396146103da578063e8111a12146103e2578063f25e55a5146103eb57600080fd5b80639cc7f7081461034e5780639e2bf22c1461036e578063a28d4c9c14610381578063a7852afa14610394578063b66503cf146103a7578063da09d19d146103ba57600080fd5b8063505897931161014b5780638dd598fb116101255780638dd598fb146102d457806392777b29146102fb5780639418f9391461032657806399bcc0521461033b57600080fd5b8063505897931461028e578063638634ee146102ae57806376f4be36146102c157600080fd5b80630175e23b1461019357806318160ddd146101b95780633e491d47146101c257806346c96aac146101d557806349dcc204146102145780634d5ce0381461025b575b600080fd5b6101a66101a1366004611792565b610476565b6040519081526020015b60405180910390f35b6101a660005481565b6101a66101d03660046117d3565b6104b8565b6101fc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101b0565b6102466102223660046117ff565b60076020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152016101b0565b61027e610269366004611821565b60066020526000908152604090205460ff1681565b60405190151581526020016101b0565b6101a661029c366004611792565b60086020526000908152604090205481565b6101a66102bc366004611821565b610741565b6101a66102cf366004611792565b610765565b6101fc7f000000000000000000000000000000000000000000000000000000000000000081565b6101a66103093660046117d3565b600260209081526000928352604080842090915290825290205481565b61033961033436600461183e565b610899565b005b6101a6610349366004611821565b610a2a565b6101a661035c366004611792565b60016020526000908152604090205481565b61033961037c3660046117ff565b610a63565b6101a661038f3660046117ff565b610b33565b6103396103a2366004611896565b610c78565b6103396103b53660046117d3565b610e78565b6101a66103c8366004611821565b60036020526000908152604090205481565b6005546101a6565b6101a6600a5481565b6101a66103f93660046117d3565b600460209081526000928352604080842090915290825290205481565b6101fc610424366004611792565b61113a565b6103396104373660046117ff565b611164565b61033961044a366004611896565b61122c565b61024661045d366004611792565b6009602052600090815260409020805460019091015482565b60008061048283611400565b9050600061049362093a808361197d565b90508084106104ae576104a98262093a8061197d565b6104b0565b815b949350505050565b6001600160a01b0382166000908152600460209081526040808320848452825280832054600890925282205482036104f457600091505061073b565b60006105008483610b33565b6000858152600860205260408120549192509061051f90600190611995565b90506000610540604051806040016040528060008152602001600081525090565b61054985611400565b81526001831561065a57845b610560600186611995565b81116106585760008981526007602090815260408083208484528252808320815180830190925280548083526001909101549282019290925291906105a490611400565b85519091508111156105c25760208501516105bf908761197d565b95505b808552600960006105d96102cf62093a808561197d565b815260200190815260200160002060010154935083600260008e6001600160a01b03166001600160a01b03168152602001908152602001600020600083815260200190815260200160002054836020015161063491906119ac565b61063e91906119e1565b602086015250819050610650816119f5565b915050610555565b505b600088815260076020908152604080832087845282528083208151808301909252805480835260019091015492820192909252919061069890611400565b905060006106a962093a808361197d565b90508042111561072f57600960006106c083610765565b815260200190815260200160002060010154600260008e6001600160a01b03166001600160a01b03168152602001908152602001600020600084815260200190815260200160002054846020015161071891906119ac565b61072291906119e1565b61072c908761197d565b95505b50939750505050505050505b92915050565b6001600160a01b03811660009081526003602052604081205461073b904290611419565b600a5460009080820361077b5750600092915050565b826009600061078b600185611995565b815260200190815260200160002060000154116107b4576107ad600182611995565b9392505050565b6000805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b548310156107ef5750600092915050565b6000806107fd600184611995565b90505b8181111561089157600060026108168484611995565b61082091906119e1565b61082a9083611995565b60008181526009602090815260409182902082518084019093528054808452600190910154918301919091529192509087900361086b575095945050505050565b805187111561087c5781935061088a565b610887600183611995565b92505b5050610800565b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166385f2aef26040518163ffffffff1660e01b81526004016020604051808303816000875af11580156108f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091d9190611a0e565b6001600160a01b0316336001600160a01b03161461096e5760405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b60448201526064015b60405180910390fd5b816001600160a01b03166005848154811061098b5761098b611a2b565b6000918252602090912001546001600160a01b0316146109aa57600080fd5b6001600160a01b03808316600090815260066020526040808220805460ff19908116909155928416825290208054909116600117905560058054829190859081106109f7576109f7611a2b565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b600080610a3642610476565b6001600160a01b039093166000908152600260209081526040808320958352949052929092205492915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a9857600080fd5b81600080828254610aa99190611995565b909155505060008181526001602052604081208054849290610acc908490611995565b9091555050600081815260016020526040902054610aeb90829061142f565b610af3611508565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56891015b60405180910390a25050565b600082815260086020526040812054808203610b5357600091505061073b565b60008481526007602052604081208491610b6e600185611995565b81526020019081526020016000206000015411610b9857610b90600182611995565b91505061073b565b6000848152600760209081526040808320838052909152902054831015610bc357600091505061073b565b600080610bd1600184611995565b90505b81811115610c6f5760006002610bea8484611995565b610bf491906119e1565b610bfe9083611995565b6000888152600760209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090879003610c495750935061073b92505050565b8051871115610c5a57819350610c68565b610c65600183611995565b92505b5050610bd4565b50949350505050565b600b54600114610c8757600080fd5b6002600b55336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cc157600080fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4d9190611a0e565b905060005b8251811015610e6d576000610d80848381518110610d7257610d72611a2b565b6020026020010151866104b8565b90504260046000868581518110610d9957610d99611a2b565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020558015610df457610df4848381518110610de557610de5611a2b565b602002602001015184836115ab565b838281518110610e0657610e06611a2b565b60200260200101516001600160a01b0316836001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc983604051610e5291815260200190565b60405180910390a35080610e65816119f5565b915050610d52565b50506001600b555050565b600b54600114610e8757600080fd5b6002600b5580610e9657600080fd5b6001600160a01b03821660009081526006602052604090205460ff16610fde57604051633af32abf60e01b81526001600160a01b0383811660048301527f00000000000000000000000000000000000000000000000000000000000000001690633af32abf90602401602060405180830381865afa158015610f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f409190611a41565b610f8c5760405162461bcd60e51b815260206004820181905260248201527f627269626520746f6b656e73206d7573742062652077686974656c69737465646044820152606401610965565b600554601011610fde5760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606401610965565b6000610fe942610476565b6001600160a01b038416600090815260026020908152604080832084845290915290205490915061101c8433308661169a565b611026838261197d565b6001600160a01b038516600090815260026020908152604080832086845290915290205561105762093a808361197d565b6001600160a01b03851660009081526003602090815260408083209390935560069052205460ff166110e9576001600160a01b0384166000818152600660205260408120805460ff191660019081179091556005805491820181559091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b03191690911790555b60408051838152602081018590526001600160a01b0386169133917f52977ea98a2220a03ee9ba5cb003ada08d394ea10155483c95dc2dc77a7eb24b910160405180910390a350506001600b555050565b6005818154811061114a57600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461119957600080fd5b816000808282546111aa919061197d565b9091555050600081815260016020526040812080548492906111cd90849061197d565b90915550506000818152600160205260409020546111ec90829061142f565b6111f4611508565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159101610b27565b600b5460011461123b57600080fd5b6002600b5560405163430c208160e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c208190604401602060405180830381865afa1580156112ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cf9190611a41565b6112d857600080fd5b60005b81518110156113f65760006113098383815181106112fb576112fb611a2b565b6020026020010151856104b8565b9050426004600085858151811061132257611322611a2b565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120888252909252902055801561137d5761137d83838151811061136e5761136e611a2b565b602002602001015133836115ab565b82828151811061138f5761138f611a2b565b60200260200101516001600160a01b0316336001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc9836040516113db91815260200190565b60405180910390a350806113ee816119f5565b9150506112db565b50506001600b5550565b600061140f62093a8083611a63565b61073b9083611995565b600081831061142857816107ad565b5090919050565b60008281526008602052604090205442908015801590611479575060008481526007602052604081208391611465600185611995565b815260200190815260200160002060000154145b156114b25760008481526007602052604081208491611499600185611995565b8152602081019190915260400160002060010155611502565b60408051808201825283815260208082018681526000888152600783528481208682529092529290209051815590516001918201556114f290829061197d565b6000858152600860205260409020555b50505050565b600a5442811580159061153a57508060096000611526600186611995565b815260200190815260200160002060000154145b1561156b57600054600960006001856115539190611995565b81526020810191909152604001600020600101555050565b604080518082018252828152600080546020808401918252868352600990529290209051815590516001918201556115a490839061197d565b600a555050565b6000836001600160a01b03163b116115c257600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161161e9190611a77565b6000604051808303816000865af19150503d806000811461165b576040519150601f19603f3d011682016040523d82523d6000602084013e611660565b606091505b509150915081801561168a57508051158061168a57508080602001905181019061168a9190611a41565b61169357600080fd5b5050505050565b6000846001600160a01b03163b116116b157600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916117159190611a77565b6000604051808303816000865af19150503d8060008114611752576040519150601f19603f3d011682016040523d82523d6000602084013e611757565b606091505b50915091508180156117815750805115806117815750808060200190518101906117819190611a41565b61178a57600080fd5b505050505050565b6000602082840312156117a457600080fd5b5035919050565b6001600160a01b03811681146117c057600080fd5b50565b80356117ce816117ab565b919050565b600080604083850312156117e657600080fd5b82356117f1816117ab565b946020939093013593505050565b6000806040838503121561181257600080fd5b50508035926020909101359150565b60006020828403121561183357600080fd5b81356107ad816117ab565b60008060006060848603121561185357600080fd5b833592506020840135611865816117ab565b91506040840135611875816117ab565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156118a957600080fd5b8235915060208084013567ffffffffffffffff808211156118c957600080fd5b818601915086601f8301126118dd57600080fd5b8135818111156118ef576118ef611880565b8060051b604051601f19603f8301168101818110858211171561191457611914611880565b60405291825284820192508381018501918983111561193257600080fd5b938501935b8285101561195757611948856117c3565b84529385019392850192611937565b8096505050505050509250929050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561199057611990611967565b500190565b6000828210156119a7576119a7611967565b500390565b60008160001904831182151516156119c6576119c6611967565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826119f0576119f06119cb565b500490565b600060018201611a0757611a07611967565b5060010190565b600060208284031215611a2057600080fd5b81516107ad816117ab565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611a5357600080fd5b815180151581146107ad57600080fd5b600082611a7257611a726119cb565b500690565b6000825160005b81811015611a985760208186018101518583015201611a7e565b81811115611aa7576000828501525b50919091019291505056fea2646970667358221220bda98a7355c3d0722af5f4e87a69803bf3eea0749d3229da5e90e446d860a20e64736f6c634300080d0033a2646970667358221220a71532f4b51c584a7b595c072e63014e5d8cb34cea77be8c0db7ec050488d4ea64736f6c634300080d0033
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061004c5760003560e01c80632a26b9eb146100515780636485f0c414610080578063b0ad856f14610093578063eb57738c146100a6575b600080fd5b61006461005f3660046101bf565b6100b9565b6040516001600160a01b03909116815260200160405180910390f35b61006461008e3660046101bf565b610116565b600154610064906001600160a01b031681565b600054610064906001600160a01b031681565b600033826040516100c990610173565b6100d4929190610284565b604051809103906000f0801580156100f0573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b0392909216918217905592915050565b6000338260405161012690610180565b610131929190610284565b604051809103906000f08015801561014d573d6000803e3d6000fd5b50600180546001600160a01b0319166001600160a01b0392909216918217905592915050565b612b66806102e183390190565b611e8380612e4783390190565b634e487b7160e01b600052604160045260246000fd5b80356001600160a01b03811681146101ba57600080fd5b919050565b600060208083850312156101d257600080fd5b823567ffffffffffffffff808211156101ea57600080fd5b818501915085601f8301126101fe57600080fd5b8135818111156102105761021061018d565b8060051b604051601f19603f830116810181811085821117156102355761023561018d565b60405291825284820192508381018501918883111561025357600080fd5b938501935b8285101561027857610269856101a3565b84529385019392850192610258565b98975050505050505050565b6001600160a01b038381168252604060208084018290528451918401829052600092858201929091906060860190855b818110156102d25785518516835294830194918301916001016102b4565b50909897505050505050505056fe60c060405260016010553480156200001657600080fd5b5060405162002b6638038062002b668339810160408190526200003991620001f8565b6001600160a01b038216608081905260408051638dd598fb60e01b81529051638dd598fb916004808201926020929091908290030181865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa9190620002e1565b6001600160a01b031660a05260005b8151811015620001bc5760006001600160a01b0316828281518110620000e357620000e362000306565b60200260200101516001600160a01b031614620001a75760016007600084848151811062000115576200011562000306565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555060068282815181106200016b576200016b62000306565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b80620001b3816200031c565b915050620000b9565b50505062000344565b80516001600160a01b0381168114620001dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200020c57600080fd5b6200021783620001c5565b602084810151919350906001600160401b03808211156200023757600080fd5b818601915086601f8301126200024c57600080fd5b815181811115620002615762000261620001e2565b8060051b604051601f19603f83011681018181108582111715620002895762000289620001e2565b604052918252848201925083810185019189831115620002a857600080fd5b938501935b82851015620002d157620002c185620001c5565b84529385019392850192620002ad565b8096505050505050509250929050565b600060208284031215620002f457600080fd5b620002ff82620001c5565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200033d57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a0516127d2620003946000396000818161042301528181610a0201528181610e82015261167801526000818161031101528181610c0d01528181610e3f015261154d01526127d26000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c80639cc7f70811610125578063e6886396116100ad578063f301af421161007c578063f301af4214610595578063f3207723146105a8578063f5f8d365146105bb578063f7412baf146105ce578063fd314098146105f557600080fd5b8063e688639614610546578063e8111a121461054e578063f122977714610557578063f25e55a51461056a57600080fd5b8063a7852afa116100f4578063a7852afa146104d1578063aa479652146104e4578063aaf5eb6814610504578063b66503cf14610513578063da09d19d1461052657600080fd5b80639cc7f7081461046b5780639ce43f901461048b5780639e2bf22c146104ab578063a28d4c9c146104be57600080fd5b80634d5ce038116101a857806368fcee1a1161017757806368fcee1a146103f857806376f4be361461040b5780638dd598fb1461041e5780639418f9391461044557806399bcc0521461045857600080fd5b80634d5ce0381461037d57806350589793146103b05780635a45d052146103d0578063638634ee146103e557600080fd5b80632ce9aead116101ef5780632ce9aead146102ae5780633b881999146102ce5780633e491d47146102f957806346c96aac1461030c57806349dcc2041461034b57600080fd5b806301316ddf1461022157806318160ddd1461026d5780631be0528914610284578063221ca18c1461028e575b600080fd5b61025361022f3660046124a7565b600e6020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152015b60405180910390f35b61027660085481565b604051908152602001610264565b61027662093a8081565b61027661029c3660046124d3565b60006020819052908152604090205481565b6102766102bc3660046124d3565b60026020526000908152604090205481565b6102766102dc3660046124a7565b600560209081526000928352604080842090915290825290205481565b6102766103073660046124a7565b610608565b6103337f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610264565b6102536103593660046124f0565b600a6020908152600092835260408084209091529082529020805460019091015482565b6103a061038b3660046124d3565b60076020526000908152604090205460ff1681565b6040519015158152602001610264565b6102766103be366004612512565b600b6020526000908152604090205481565b6103e36103de3660046124a7565b610864565b005b6102766103f33660046124d3565b61089c565b6103e36104063660046124a7565b6108c0565b610276610419366004612512565b6108cc565b6103337f000000000000000000000000000000000000000000000000000000000000000081565b6103e361045336600461252b565b610a00565b6102766104663660046124d3565b610b91565b610276610479366004612512565b60096020526000908152604090205481565b6102766104993660046124d3565b60036020526000908152604090205481565b6103e36104b93660046124f0565b610c02565b6102766104cc3660046124f0565b610cdb565b6103e36104df366004612583565b610e20565b6102766104f23660046124d3565b600f6020526000908152604090205481565b610276670de0b6b3a764000081565b6103e36105213660046124a7565b611165565b6102766105343660046124d3565b60016020526000908152604090205481565b600654610276565b610276600d5481565b6102766105653660046124d3565b61145b565b6102766105783660046124a7565b600460209081526000928352604080842090915290825290205481565b6103336105a3366004612512565b611518565b6103e36105b63660046124f0565b611542565b6103e36105c9366004612583565b611648565b6102536105dc366004612512565b600c602052600090815260409020805460019091015482565b6102536106033660046124a7565b61194f565b6001600160a01b0382166000818152600460209081526040808320858452825280832054938352600e82528083208380529091528120549091829161064d9190611b70565b6000848152600b60205260408120549192500361066e57600091505061085e565b600061067a8483610cdb565b6000858152600b6020526040812054919250906106999060019061266a565b9050600081156107a257825b6106b060018461266a565b81116107a0576000878152600a60208181526040808420858552808352818520825180840190935280548352600190810154838501528c865293909252929182906106fc908690612681565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600061073b8b846000015161194f565b509050600061074e8c846000015161194f565b509050670de0b6b3a7640000610764838361266a565b85602001516107739190612699565b61077d91906126b8565b6107879087612681565b9550505050508080610798906126da565b9150506106a5565b505b6000868152600a602090815260408083208584528252808320815180830190925280548083526001909101549282019290925291906107e2908a9061194f565b506001600160a01b038a1660009081526005602090815260408083208c8452909152902054909150670de0b6b3a76400009061081f908390611b70565b6108288b61145b565b610832919061266a565b83602001516108419190612699565b61084b91906126b8565b6108559084612681565b96505050505050505b92915050565b61086e8282611b87565b6001600160a01b03909316600090815260036020908152604080832060029092529091209390935590915550565b6001600160a01b03811660009081526001602052604081205461085e904290611cea565b61086e82826000611cf9565b600d546000908082036108e25750600092915050565b82600c60006108f260018561266a565b8152602001908152602001600020600001541161091b5761091460018261266a565b9392505050565b60008052600c6020527f13649b2456f1b42fef0f0040b3aaeabcd21a76a0f3f5defd4f583839455116e8548310156109565750600092915050565b60008061096460018461266a565b90505b818111156109f8576000600261097d848461266a565b61098791906126b8565b610991908361266a565b6000818152600c60209081526040918290208251808401909352805480845260019091015491830191909152919250908790036109d2575095945050505050565b80518711156109e3578193506109f1565b6109ee60018361266a565b92505b5050610967565b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166385f2aef26040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610a60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8491906126f3565b6001600160a01b0316336001600160a01b031614610ad55760405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b60448201526064015b60405180910390fd5b816001600160a01b031660068481548110610af257610af2612710565b6000918252602090912001546001600160a01b031614610b1157600080fd5b6001600160a01b03808316600090815260076020526040808220805460ff1990811690915592841682529020805490911660011790556006805482919085908110610b5e57610b5e612710565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b6001600160a01b0381166000908152600160205260408120544210610bb857506000919050565b6001600160a01b038216600090815260016020526040812054610bdc90429061266a565b6001600160a01b0384166000908152602081905260409020549091506109149082612699565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610c3757600080fd5b610c3f611ee9565b8160086000828254610c51919061266a565b909155505060008181526009602052604081208054849290610c7490849061266a565b9091555050600081815260096020526040902054610c93908290611f71565b610c9b61204a565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56891015b60405180910390a25050565b6000828152600b6020526040812054808203610cfb57600091505061085e565b6000848152600a602052604081208491610d1660018561266a565b81526020019081526020016000206000015411610d4057610d3860018261266a565b91505061085e565b6000848152600a60209081526040808320838052909152902054831015610d6b57600091505061085e565b600080610d7960018461266a565b90505b81811115610e175760006002610d92848461266a565b610d9c91906126b8565b610da6908361266a565b6000888152600a60209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090879003610df15750935061085e92505050565b8051871115610e0257819350610e10565b610e0d60018361266a565b92505b5050610d7c565b50949350505050565b601054600114610e2f57600080fd5b6002601055336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e6957600080fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610ed1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef591906126f3565b905060005b825181101561115a57610f2a838281518110610f1857610f18612710565b60200260200101516000196001611cf9565b60036000868581518110610f4057610f40612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600060026000888781518110610f8057610f80612710565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060008491905055839190505550506000610fdb848381518110610fcd57610fcd612710565b602002602001015186610608565b90504260046000868581518110610ff457610ff4612710565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000878152602001908152602001600020819055506003600085848151811061104757611047612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546005600086858151811061108657611086612710565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812089825290925290205580156110e1576110e18483815181106110d2576110d2612710565b602002602001015184836120ee565b8382815181106110f3576110f3612710565b60200260200101516001600160a01b0316836001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc98360405161113f91815260200190565b60405180910390a35080611152816126da565b915050610efa565b505060016010555050565b60105460011461117457600080fd5b60026010558061118357600080fd5b6001600160a01b03821660009081526007602052604090205460ff166111a857600080fd5b6001600160a01b03821660009081526020819052604081205490036111d3576111d3826000426121dd565b6111e1826000196001611cf9565b6001600160a01b038416600090815260036020908152604080832060028352818420949094559390925560019091522054421061124f57611224823330846122cc565b61123162093a80826126b8565b6001600160a01b0383166000908152602081905260409020556112e8565b6001600160a01b03821660009081526001602052604081205461127390429061266a565b6001600160a01b0384166000908152602081905260408120549192509061129a9083612699565b90508083116112a857600080fd5b6112b4843330866122cc565b62093a806112c28285612681565b6112cc91906126b8565b6001600160a01b03851660009081526020819052604090205550505b6001600160a01b03821660009081526020819052604090205461130a57600080fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015611351573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113759190612726565b905061138462093a80826126b8565b6001600160a01b03841660009081526020819052604090205411156113eb5760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f206869676800000000000000006044820152606401610acc565b6113f862093a8042612681565b6001600160a01b0384166000818152600160205260409081902092909255905133907ff70d5c697de7ea828df48e5c4573cb2194c659f1901f70110c52b066dcf50826906114499086815260200190565b60405180910390a35050600160105550565b600060085460000361148357506001600160a01b031660009081526003602052604090205490565b6008546001600160a01b0383166000908152602081815260408083205460028352818420546001909352922054670de0b6b3a764000092916114c491611cea565b6114cd8661089c565b6114d7919061266a565b6114e19190612699565b6114eb9190612699565b6114f591906126b8565b6001600160a01b03831660009081526003602052604090205461085e9190612681565b6006818154811061152857600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146115ac5760405162461bcd60e51b815260206004820152600f60248201526e3737ba10313934b132903b37ba32b960891b6044820152606401610acc565b6115b4611ee9565b81600860008282546115c69190612681565b9091555050600081815260096020526040812080548492906115e9908490612681565b9091555050600081815260096020526040902054611608908290611f71565b61161061204a565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159101610ccf565b60105460011461165757600080fd5b600260105560405163430c208160e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c208190604401602060405180830381865afa1580156116c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116eb919061273f565b6116f457600080fd5b60005b815181101561194557611715828281518110610f1857610f18612710565b6003600085858151811061172b5761172b612710565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006002600087878151811061176b5761176b612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020600084919050558391905055505060006117c68383815181106117b8576117b8612710565b602002602001015185610608565b905042600460008585815181106117df576117df612710565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000868152602001908152602001600020819055506003600084848151811061183257611832612710565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546005600085858151811061187157611871612710565b6020908102919091018101516001600160a01b03168252818101929092526040908101600090812088825290925290205580156118cc576118cc8383815181106118bd576118bd612710565b602002602001015133836120ee565b8282815181106118de576118de612710565b60200260200101516001600160a01b0316336001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc98360405161192a91815260200190565b60405180910390a3508061193d816126da565b9150506116f7565b5050600160105550565b6001600160a01b0382166000908152600f6020526040812054819080820361197e576000809250925050611b69565b6001600160a01b0385166000908152600e6020526040812085916119a360018561266a565b81526020019081526020016000206000015411611a40576001600160a01b0385166000908152600e60205260408120906119de60018461266a565b815260200190815260200160002060010154600e6000876001600160a01b03166001600160a01b031681526020019081526020016000206000600184611a24919061266a565b8152602001908152602001600020600001549250925050611b69565b6001600160a01b0385166000908152600e60209081526040808320838052909152902054841015611a78576000809250925050611b69565b600080611a8660018461266a565b90505b81811115611b385760006002611a9f848461266a565b611aa991906126b8565b611ab3908361266a565b6001600160a01b0389166000908152600e60209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090889003611b1257602081015190519096509450611b699350505050565b8051881115611b2357819350611b31565b611b2e60018361266a565b92505b5050611a89565b506001600160a01b0386166000908152600e6020908152604080832093835292905220600181015490549093509150505b9250929050565b600081831015611b805781610914565b5090919050565b6001600160a01b0382166000908152600260209081526040808320546003909252822054600d54839291908303611bc15792509050611b69565b6001600160a01b0386166000908152602081905260408120549003611bec579250429150611b699050565b6000611bf7836108cc565b90506000611c136001600d54611c0d919061266a565b88611cea565b9050815b81811015611cdb576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611cc8576000600c81611c5c856001612681565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600080611ca78d8460000151866000015187602001518d6123c4565b9092509050611cb68289612681565b9750611cc38d89836121dd565b975050505b5080611cd3816126da565b915050611c17565b50919792965091945050505050565b6000818310611b805781610914565b6001600160a01b0383166000908152600260209081526040808320546003909252822054600d54839291908303611d335792509050611ee1565b6001600160a01b0387166000908152602081905260408120549003611d5e579250429150611ee19050565b6000611d69836108cc565b90506000611d856001600d54611d7f919061266a565b89611cea565b90508015611e5e57815b611d9a60018361266a565b8111611e5c576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611e49576000600c81611ddd856001612681565b8152602001908152602001600020604051806040016040529081600082015481526020016001820154815250509050600080611e288e8460000151866000015187602001518d6123c4565b9092509050611e378289612681565b9750611e448e89836121dd565b975050505b5080611e54816126da565b915050611d8f565b505b8615611ed8576000818152600c60209081526040918290208251808401909352805483526001015490820181905215611ed6576000611eb78b611ea08d61089c565b8451611eac908a611b70565b85602001518a6123c4565b509050611ec48186612681565b9450611ed18b86426121dd565b429550505b505b50909350909150505b935093915050565b60065460005b81811015611f6d57600060068281548110611f0c57611f0c612710565b6000918252602090912001546001600160a01b03169050611f31816000196001611cf9565b6001600160a01b039092166000908152600360209081526040808320600290925290912092909255905580611f65816126da565b915050611eef565b5050565b6000828152600b602052604090205442908015801590611fbb57506000848152600a602052604081208391611fa760018561266a565b815260200190815260200160002060000154145b15611ff4576000848152600a602052604081208491611fdb60018561266a565b8152602081019190915260400160002060010155612044565b60408051808201825283815260208082018681526000888152600a8352848120868252909252929020905181559051600191820155612034908290612681565b6000858152600b60205260409020555b50505050565b600d5442811580159061207c575080600c600061206860018661266a565b815260200190815260200160002060000154145b156120ab57600854600c600061209360018661266a565b81526020810191909152604001600020600101555050565b60408051808201825282815260085460208083019182526000868152600c909152929092209051815590516001918201556120e7908390612681565b600d555050565b6000836001600160a01b03163b1161210557600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392908716916121619190612761565b6000604051808303816000865af19150503d806000811461219e576040519150601f19603f3d011682016040523d82523d6000602084013e6121a3565b606091505b50915091508180156121cd5750805115806121cd5750808060200190518101906121cd919061273f565b6121d657600080fd5b5050505050565b6001600160a01b0383166000908152600f6020526040902054801580159061223957506001600160a01b0384166000908152600e60205260408120839161222560018561266a565b815260200190815260200160002060000154145b15612263576001600160a01b0384166000908152600e602052604081208491611fdb60018561266a565b60408051808201825283815260208082018681526001600160a01b0388166000908152600e83528481208682529092529290209051815590516001918201556122ad908290612681565b6001600160a01b0385166000908152600f602052604090205550505050565b6000846001600160a01b03163b116122e357600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916123479190612761565b6000604051808303816000865af19150503d8060008114612384576040519150601f19603f3d011682016040523d82523d6000602084013e612389565b606091505b50915091508180156123b35750805115806123b35750808060200190518101906123b3919061273f565b6123bc57600080fd5b505050505050565b60008060006123d38785611b70565b6001600160a01b0389166000908152602081905260409020549091508590670de0b6b3a7640000906124266124088a89611b70565b6001600160a01b038d16600090815260016020526040902054611cea565b6001600160a01b038c1660009081526001602052604090205461244a908690611cea565b612454919061266a565b61245e9190612699565b6124689190612699565b61247291906126b8565b9890975095505050505050565b6001600160a01b038116811461249457600080fd5b50565b80356124a28161247f565b919050565b600080604083850312156124ba57600080fd5b82356124c58161247f565b946020939093013593505050565b6000602082840312156124e557600080fd5b81356109148161247f565b6000806040838503121561250357600080fd5b50508035926020909101359150565b60006020828403121561252457600080fd5b5035919050565b60008060006060848603121561254057600080fd5b8335925060208401356125528161247f565b915060408401356125628161247f565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b6000806040838503121561259657600080fd5b8235915060208084013567ffffffffffffffff808211156125b657600080fd5b818601915086601f8301126125ca57600080fd5b8135818111156125dc576125dc61256d565b8060051b604051601f19603f830116810181811085821117156126015761260161256d565b60405291825284820192508381018501918983111561261f57600080fd5b938501935b828510156126445761263585612497565b84529385019392850192612624565b8096505050505050509250929050565b634e487b7160e01b600052601160045260246000fd5b60008282101561267c5761267c612654565b500390565b6000821982111561269457612694612654565b500190565b60008160001904831182151516156126b3576126b3612654565b500290565b6000826126d557634e487b7160e01b600052601260045260246000fd5b500490565b6000600182016126ec576126ec612654565b5060010190565b60006020828403121561270557600080fd5b81516109148161247f565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561273857600080fd5b5051919050565b60006020828403121561275157600080fd5b8151801515811461091457600080fd5b6000825160005b818110156127825760208186018101518583015201612768565b81811115612791576000828501525b50919091019291505056fea2646970667358221220edc839d72bbcddae86ef704bcf28c42aed623358aa6831ada7e5f16192a1458064736f6c634300080d003360c06040526001600b553480156200001657600080fd5b5060405162001e8338038062001e838339810160408190526200003991620001f8565b6001600160a01b038216608081905260408051638dd598fb60e01b81529051638dd598fb916004808201926020929091908290030181865afa15801562000084573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000aa9190620002e1565b6001600160a01b031660a05260005b8151811015620001bc5760006001600160a01b0316828281518110620000e357620000e362000306565b60200260200101516001600160a01b031614620001a75760016006600084848151811062000115576200011562000306565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555060058282815181106200016b576200016b62000306565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790555b80620001b3816200031c565b915050620000b9565b50505062000344565b80516001600160a01b0381168114620001dd57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200020c57600080fd5b6200021783620001c5565b602084810151919350906001600160401b03808211156200023757600080fd5b818601915086601f8301126200024c57600080fd5b815181811115620002615762000261620001e2565b8060051b604051601f19603f83011681018181108582111715620002895762000289620001e2565b604052918252848201925083810185019189831115620002a857600080fd5b938501935b82851015620002d157620002c185620001c5565b84529385019392850192620002ad565b8096505050505050509250929050565b600060208284031215620002f457600080fd5b620002ff82620001c5565b9392505050565b634e487b7160e01b600052603260045260246000fd5b6000600182016200033d57634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a051611ae86200039b600039600081816102d90152818161089b01528181610cda015261125c0152600081816101da01528181610a6e01528181610c9701528181610ed5015261116f0152611ae86000f3fe608060405234801561001057600080fd5b506004361061018e5760003560e01c80639cc7f708116100de578063e688639611610097578063f301af4211610071578063f301af4214610416578063f320772314610429578063f5f8d3651461043c578063f7412baf1461044f57600080fd5b8063e6886396146103da578063e8111a12146103e2578063f25e55a5146103eb57600080fd5b80639cc7f7081461034e5780639e2bf22c1461036e578063a28d4c9c14610381578063a7852afa14610394578063b66503cf146103a7578063da09d19d146103ba57600080fd5b8063505897931161014b5780638dd598fb116101255780638dd598fb146102d457806392777b29146102fb5780639418f9391461032657806399bcc0521461033b57600080fd5b8063505897931461028e578063638634ee146102ae57806376f4be36146102c157600080fd5b80630175e23b1461019357806318160ddd146101b95780633e491d47146101c257806346c96aac146101d557806349dcc204146102145780634d5ce0381461025b575b600080fd5b6101a66101a1366004611792565b610476565b6040519081526020015b60405180910390f35b6101a660005481565b6101a66101d03660046117d3565b6104b8565b6101fc7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101b0565b6102466102223660046117ff565b60076020908152600092835260408084209091529082529020805460019091015482565b604080519283526020830191909152016101b0565b61027e610269366004611821565b60066020526000908152604090205460ff1681565b60405190151581526020016101b0565b6101a661029c366004611792565b60086020526000908152604090205481565b6101a66102bc366004611821565b610741565b6101a66102cf366004611792565b610765565b6101fc7f000000000000000000000000000000000000000000000000000000000000000081565b6101a66103093660046117d3565b600260209081526000928352604080842090915290825290205481565b61033961033436600461183e565b610899565b005b6101a6610349366004611821565b610a2a565b6101a661035c366004611792565b60016020526000908152604090205481565b61033961037c3660046117ff565b610a63565b6101a661038f3660046117ff565b610b33565b6103396103a2366004611896565b610c78565b6103396103b53660046117d3565b610e78565b6101a66103c8366004611821565b60036020526000908152604090205481565b6005546101a6565b6101a6600a5481565b6101a66103f93660046117d3565b600460209081526000928352604080842090915290825290205481565b6101fc610424366004611792565b61113a565b6103396104373660046117ff565b611164565b61033961044a366004611896565b61122c565b61024661045d366004611792565b6009602052600090815260409020805460019091015482565b60008061048283611400565b9050600061049362093a808361197d565b90508084106104ae576104a98262093a8061197d565b6104b0565b815b949350505050565b6001600160a01b0382166000908152600460209081526040808320848452825280832054600890925282205482036104f457600091505061073b565b60006105008483610b33565b6000858152600860205260408120549192509061051f90600190611995565b90506000610540604051806040016040528060008152602001600081525090565b61054985611400565b81526001831561065a57845b610560600186611995565b81116106585760008981526007602090815260408083208484528252808320815180830190925280548083526001909101549282019290925291906105a490611400565b85519091508111156105c25760208501516105bf908761197d565b95505b808552600960006105d96102cf62093a808561197d565b815260200190815260200160002060010154935083600260008e6001600160a01b03166001600160a01b03168152602001908152602001600020600083815260200190815260200160002054836020015161063491906119ac565b61063e91906119e1565b602086015250819050610650816119f5565b915050610555565b505b600088815260076020908152604080832087845282528083208151808301909252805480835260019091015492820192909252919061069890611400565b905060006106a962093a808361197d565b90508042111561072f57600960006106c083610765565b815260200190815260200160002060010154600260008e6001600160a01b03166001600160a01b03168152602001908152602001600020600084815260200190815260200160002054846020015161071891906119ac565b61072291906119e1565b61072c908761197d565b95505b50939750505050505050505b92915050565b6001600160a01b03811660009081526003602052604081205461073b904290611419565b600a5460009080820361077b5750600092915050565b826009600061078b600185611995565b815260200190815260200160002060000154116107b4576107ad600182611995565b9392505050565b6000805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b548310156107ef5750600092915050565b6000806107fd600184611995565b90505b8181111561089157600060026108168484611995565b61082091906119e1565b61082a9083611995565b60008181526009602090815260409182902082518084019093528054808452600190910154918301919091529192509087900361086b575095945050505050565b805187111561087c5781935061088a565b610887600183611995565b92505b5050610800565b509392505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166385f2aef26040518163ffffffff1660e01b81526004016020604051808303816000875af11580156108f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061091d9190611a0e565b6001600160a01b0316336001600160a01b03161461096e5760405162461bcd60e51b81526020600482015260096024820152686f6e6c79207465616d60b81b60448201526064015b60405180910390fd5b816001600160a01b03166005848154811061098b5761098b611a2b565b6000918252602090912001546001600160a01b0316146109aa57600080fd5b6001600160a01b03808316600090815260066020526040808220805460ff19908116909155928416825290208054909116600117905560058054829190859081106109f7576109f7611a2b565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550505050565b600080610a3642610476565b6001600160a01b039093166000908152600260209081526040808320958352949052929092205492915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a9857600080fd5b81600080828254610aa99190611995565b909155505060008181526001602052604081208054849290610acc908490611995565b9091555050600081815260016020526040902054610aeb90829061142f565b610af3611508565b604080518281526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56891015b60405180910390a25050565b600082815260086020526040812054808203610b5357600091505061073b565b60008481526007602052604081208491610b6e600185611995565b81526020019081526020016000206000015411610b9857610b90600182611995565b91505061073b565b6000848152600760209081526040808320838052909152902054831015610bc357600091505061073b565b600080610bd1600184611995565b90505b81811115610c6f5760006002610bea8484611995565b610bf491906119e1565b610bfe9083611995565b6000888152600760209081526040808320848452825291829020825180840190935280548084526001909101549183019190915291925090879003610c495750935061073b92505050565b8051871115610c5a57819350610c68565b610c65600183611995565b92505b5050610bd4565b50949350505050565b600b54600114610c8757600080fd5b6002600b55336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610cc157600080fd5b6040516331a9108f60e11b8152600481018390526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610d29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4d9190611a0e565b905060005b8251811015610e6d576000610d80848381518110610d7257610d72611a2b565b6020026020010151866104b8565b90504260046000868581518110610d9957610d99611a2b565b6020908102919091018101516001600160a01b0316825281810192909252604090810160009081208982529092529020558015610df457610df4848381518110610de557610de5611a2b565b602002602001015184836115ab565b838281518110610e0657610e06611a2b565b60200260200101516001600160a01b0316836001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc983604051610e5291815260200190565b60405180910390a35080610e65816119f5565b915050610d52565b50506001600b555050565b600b54600114610e8757600080fd5b6002600b5580610e9657600080fd5b6001600160a01b03821660009081526006602052604090205460ff16610fde57604051633af32abf60e01b81526001600160a01b0383811660048301527f00000000000000000000000000000000000000000000000000000000000000001690633af32abf90602401602060405180830381865afa158015610f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f409190611a41565b610f8c5760405162461bcd60e51b815260206004820181905260248201527f627269626520746f6b656e73206d7573742062652077686974656c69737465646044820152606401610965565b600554601011610fde5760405162461bcd60e51b815260206004820152601760248201527f746f6f206d616e79207265776172647320746f6b656e730000000000000000006044820152606401610965565b6000610fe942610476565b6001600160a01b038416600090815260026020908152604080832084845290915290205490915061101c8433308661169a565b611026838261197d565b6001600160a01b038516600090815260026020908152604080832086845290915290205561105762093a808361197d565b6001600160a01b03851660009081526003602090815260408083209390935560069052205460ff166110e9576001600160a01b0384166000818152600660205260408120805460ff191660019081179091556005805491820181559091527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db00180546001600160a01b03191690911790555b60408051838152602081018590526001600160a01b0386169133917f52977ea98a2220a03ee9ba5cb003ada08d394ea10155483c95dc2dc77a7eb24b910160405180910390a350506001600b555050565b6005818154811061114a57600080fd5b6000918252602090912001546001600160a01b0316905081565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461119957600080fd5b816000808282546111aa919061197d565b9091555050600081815260016020526040812080548492906111cd90849061197d565b90915550506000818152600160205260409020546111ec90829061142f565b6111f4611508565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159101610b27565b600b5460011461123b57600080fd5b6002600b5560405163430c208160e01b8152336004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c208190604401602060405180830381865afa1580156112ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112cf9190611a41565b6112d857600080fd5b60005b81518110156113f65760006113098383815181106112fb576112fb611a2b565b6020026020010151856104b8565b9050426004600085858151811061132257611322611a2b565b6020908102919091018101516001600160a01b031682528181019290925260409081016000908120888252909252902055801561137d5761137d83838151811061136e5761136e611a2b565b602002602001015133836115ab565b82828151811061138f5761138f611a2b565b60200260200101516001600160a01b0316336001600160a01b03167f9aa05b3d70a9e3e2f004f039648839560576334fb45c81f91b6db03ad9e2efc9836040516113db91815260200190565b60405180910390a350806113ee816119f5565b9150506112db565b50506001600b5550565b600061140f62093a8083611a63565b61073b9083611995565b600081831061142857816107ad565b5090919050565b60008281526008602052604090205442908015801590611479575060008481526007602052604081208391611465600185611995565b815260200190815260200160002060000154145b156114b25760008481526007602052604081208491611499600185611995565b8152602081019190915260400160002060010155611502565b60408051808201825283815260208082018681526000888152600783528481208682529092529290209051815590516001918201556114f290829061197d565b6000858152600860205260409020555b50505050565b600a5442811580159061153a57508060096000611526600186611995565b815260200190815260200160002060000154145b1561156b57600054600960006001856115539190611995565b81526020810191909152604001600020600101555050565b604080518082018252828152600080546020808401918252868352600990529290209051815590516001918201556115a490839061197d565b600a555050565b6000836001600160a01b03163b116115c257600080fd5b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929087169161161e9190611a77565b6000604051808303816000865af19150503d806000811461165b576040519150601f19603f3d011682016040523d82523d6000602084013e611660565b606091505b509150915081801561168a57508051158061168a57508080602001905181019061168a9190611a41565b61169357600080fd5b5050505050565b6000846001600160a01b03163b116116b157600080fd5b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b17905291516000928392908816916117159190611a77565b6000604051808303816000865af19150503d8060008114611752576040519150601f19603f3d011682016040523d82523d6000602084013e611757565b606091505b50915091508180156117815750805115806117815750808060200190518101906117819190611a41565b61178a57600080fd5b505050505050565b6000602082840312156117a457600080fd5b5035919050565b6001600160a01b03811681146117c057600080fd5b50565b80356117ce816117ab565b919050565b600080604083850312156117e657600080fd5b82356117f1816117ab565b946020939093013593505050565b6000806040838503121561181257600080fd5b50508035926020909101359150565b60006020828403121561183357600080fd5b81356107ad816117ab565b60008060006060848603121561185357600080fd5b833592506020840135611865816117ab565b91506040840135611875816117ab565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156118a957600080fd5b8235915060208084013567ffffffffffffffff808211156118c957600080fd5b818601915086601f8301126118dd57600080fd5b8135818111156118ef576118ef611880565b8060051b604051601f19603f8301168101818110858211171561191457611914611880565b60405291825284820192508381018501918983111561193257600080fd5b938501935b8285101561195757611948856117c3565b84529385019392850192611937565b8096505050505050509250929050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561199057611990611967565b500190565b6000828210156119a7576119a7611967565b500390565b60008160001904831182151516156119c6576119c6611967565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826119f0576119f06119cb565b500490565b600060018201611a0757611a07611967565b5060010190565b600060208284031215611a2057600080fd5b81516107ad816117ab565b634e487b7160e01b600052603260045260246000fd5b600060208284031215611a5357600080fd5b815180151581146107ad57600080fd5b600082611a7257611a726119cb565b500690565b6000825160005b81811015611a985760208186018101518583015201611a7e565b81811115611aa7576000828501525b50919091019291505056fea2646970667358221220bda98a7355c3d0722af5f4e87a69803bf3eea0749d3229da5e90e446d860a20e64736f6c634300080d0033a2646970667358221220a71532f4b51c584a7b595c072e63014e5d8cb34cea77be8c0db7ec050488d4ea64736f6c634300080d0033