Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- BoostedNETTFarm
- Optimization enabled
- true
- Compiler version
- v0.6.12+commit.27d51765
- Optimization runs
- 9999
- Verified at
- 2022-11-30T15:39:36.842499Z
contracts/BoostedNETTFarm.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; pragma experimental ABIEncoderV2; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "./interfaces/IERC20.sol"; import "./interfaces/INETTFarm.sol"; import "./interfaces/IRewarder.sol"; import "./libs/BoringNETTERC20.sol"; import "./libs/Math.sol"; /// @notice The (older) NETTFarm contract gives out a constant number of NETT /// tokens per sec. The idea for this BoostedNETTFarm (BNTF) contract is /// therefore to be the owner of a dummy token that is deposited into the NETTFarm (NTF) contract. /// The allocation point for this pool on NTF is the total allocation point for all pools on BNTF. /// /// This NETTFarm also skews how many rewards users receive, it does this by /// modifying the algorithm that calculates how many tokens are rewarded to /// depositors. Whereas NETTFarm calculates rewards based on emission rate and /// total liquidity, this version uses adjusted parameters to this calculation. /// /// A users `boostedAmount` (liquidity multiplier) is calculated by the actual supplied /// liquidity multiplied by a boost factor. The boost factor is calculated by the /// amount of veNETT held by the user over the total veNETT amount held by all pool /// participants. Total liquidity is the sum of all boosted liquidity. contract BoostedNETTFarm is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable { using BoringNETTERC20 for IERC20; using SafeMathUpgradeable for uint256; /// @notice Info of each BNTF user /// `amount` LP token amount the user has provided /// `rewardDebt` The amount of NETT entitled to the user /// `factor` the users factor, use _getUserFactor struct UserInfo { uint256 amount; uint256 rewardDebt; uint256 factor; } /// @notice Info of each BNTF pool /// `allocPoint` The amount of allocation points assigned to the pool /// Also known as the amount of NETT to distribute per sec struct PoolInfo { // Address are stored in 160 bits, so we store allocPoint in 96 bits to // optimize storage (160 + 96 = 256) IERC20 lpToken; uint96 allocPoint; uint256 accNETTPerShare; uint256 accNETTPerFactorPerShare; // Address are stored in 160 bits, so we store lastRewardTimestamp in 64 bits and // veNETTShareBp in 32 bits to optimize storage (160 + 64 + 32 = 256) uint64 lastRewardTimestamp; IRewarder rewarder; // Share of the reward to distribute to veNETT holders uint32 veNETTShareBp; // The sum of all veNETT held by users participating in this farm // This value is updated when // - A user enter/leaves a farm // - A user claims veNETT // - A user unstakes NETT uint256 totalFactor; // The total LP supply of the farm // This is the sum of all users boosted amounts in the farm. Updated when // someone deposits or withdraws. // This is used instead of the usual `lpToken.balanceOf(address(this))` for security reasons uint256 totalLpSupply; } /// @notice Address of NTF contract INETTFarm public NETTFarm; /// @notice Address of NETT contract IERC20 public NETT; /// @notice Address of veNETT contract IERC20 public VENETT; /// @notice The index of BNTF master pool in NTF uint256 public MASTER_PID; /// @notice Info of each BNTF pool PoolInfo[] public poolInfo; /// @dev Maps an address to a bool to assert that a token isn't added twice mapping(IERC20 => bool) private checkPoolDuplicate; /// @notice Info of each user that stakes LP tokens mapping(uint256 => mapping(address => UserInfo)) public userInfo; /// @dev Total allocation points. Must be the sum of all allocation points in all pools uint256 public totalAllocPoint; uint256 private ACC_TOKEN_PRECISION; /// @dev Amount of claimable NETT the user has, this is required as we /// need to update rewardDebt after a token operation but we don't /// want to send a reward at this point. This amount gets added onto /// the pending amount when a user claims mapping(uint256 => mapping(address => uint256)) public claimableNETT; event Add( uint256 indexed pid, uint256 allocPoint, uint256 veNETTShareBp, IERC20 indexed lpToken, IRewarder indexed rewarder ); event Set( uint256 indexed pid, uint256 allocPoint, uint256 veNETTShareBp, IRewarder indexed rewarder, bool overwrite ); event Deposit(address indexed user, uint256 indexed pid, uint256 amount); event Withdraw(address indexed user, uint256 indexed pid, uint256 amount); event UpdatePool( uint256 indexed pid, uint256 lastRewardTimestamp, uint256 lpSupply, uint256 accNETTPerShare, uint256 accNETTPerFactorPerShare ); event Harvest(address indexed user, uint256 indexed pid, uint256 amount); event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount); event Init(uint256 amount); /// @param _NETTFarm The NETTFarm contract address /// @param _nett The NETT contract address /// @param _veNETT The veNETT contract address /// @param _MASTER_PID The pool ID of the dummy token on the base NETTFarm contract function initialize( INETTFarm _NETTFarm, IERC20 _nett, IERC20 _veNETT, uint256 _MASTER_PID ) public initializer { __Ownable_init(); NETTFarm = _NETTFarm; NETT = _nett; VENETT = _veNETT; MASTER_PID = _MASTER_PID; ACC_TOKEN_PRECISION = 1e18; } /// @notice Deposits a dummy token to `NETTFarm` NTF. This is required because NTF /// holds the minting rights for NETT. Any balance of transaction sender in `_dummyToken` is transferred. /// The allocation point for the pool on NTF is the total allocation point for all pools that receive /// double incentives. /// @param _dummyToken The address of the ERC-20 token to deposit into NTF. function init(IERC20 _dummyToken) external onlyOwner { require( _dummyToken.balanceOf(address(NETTFarm)) == 0, "BoostedNETTFarm: Already has a balance of dummy token" ); uint256 balance = _dummyToken.balanceOf(_msgSender()); require(balance != 0, "BoostedNETTFarm: Balance must exceed 0"); _dummyToken.safeTransferFrom(_msgSender(), address(this), balance); _dummyToken.approve(address(NETTFarm), balance); NETTFarm.deposit(MASTER_PID, balance); emit Init(balance); } /// @notice Add a new LP to the pool. Can only be called by the owner. /// @param _allocPoint AP of the new pool. /// @param _veNETTShareBp Share of rewards allocated in proportion to user's liquidity /// and veNETT balance /// @param _lpToken Address of the LP ERC-20 token. /// @param _rewarder Address of the rewarder delegate. function add( uint96 _allocPoint, uint32 _veNETTShareBp, IERC20 _lpToken, IRewarder _rewarder ) external onlyOwner { require(!checkPoolDuplicate[_lpToken], "BoostedNETTFarm: LP already added"); require(_veNETTShareBp <= 10_000, "BoostedNETTFarm: veNETTShareBp needs to be lower than 10000"); require(poolInfo.length <= 50, "BoostedNETTFarm: Too many pools"); checkPoolDuplicate[_lpToken] = true; // Sanity check to ensure _lpToken is an ERC20 token _lpToken.balanceOf(address(this)); // Sanity check if we add a rewarder if (address(_rewarder) != address(0)) { _rewarder.onNETTReward(address(0), 0); } massUpdatePools(); totalAllocPoint = totalAllocPoint.add(_allocPoint); poolInfo.push( PoolInfo({ lpToken: _lpToken, allocPoint: _allocPoint, accNETTPerShare: 0, accNETTPerFactorPerShare: 0, lastRewardTimestamp: uint64(block.timestamp), rewarder: _rewarder, veNETTShareBp: _veNETTShareBp, totalFactor: 0, totalLpSupply: 0 }) ); emit Add(poolInfo.length - 1, _allocPoint, _veNETTShareBp, _lpToken, _rewarder); } /// @notice Update the given pool's NETT allocation point and `IRewarder` contract. Can only be called by the owner. /// @param _pid The index of the pool. See `poolInfo` /// @param _allocPoint New AP of the pool /// @param _veNETTShareBp Share of rewards allocated in proportion to user's liquidity /// and veNETT balance /// @param _rewarder Address of the rewarder delegate /// @param _overwrite True if _rewarder should be `set`. Otherwise `_rewarder` is ignored function set( uint256 _pid, uint96 _allocPoint, uint32 _veNETTShareBp, IRewarder _rewarder, bool _overwrite ) external onlyOwner { require(_veNETTShareBp <= 10_000, "BoostedNETTFarm: veNETTShareBp needs to be lower than 10000"); massUpdatePools(); PoolInfo storage pool = poolInfo[_pid]; totalAllocPoint = totalAllocPoint.add(_allocPoint).sub(pool.allocPoint); pool.allocPoint = _allocPoint; pool.veNETTShareBp = _veNETTShareBp; if (_overwrite) { if (address(_rewarder) != address(0)) { // Sanity check _rewarder.onNETTReward(address(0), 0); } pool.rewarder = _rewarder; } emit Set(_pid, _allocPoint, _veNETTShareBp, _overwrite ? _rewarder : pool.rewarder, _overwrite); } /// @notice Deposit LP tokens to BNTF for NETT allocation /// @param _pid The index of the pool. See `poolInfo` /// @param _amount LP token amount to deposit function deposit(uint256 _pid, uint256 _amount) external nonReentrant { harvestFromNETTFarm(); updatePool(_pid); PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_msgSender()]; // Pay a user any pending rewards if (user.amount != 0) { _harvestNETT(user, pool, _pid); } uint256 balanceBefore = pool.lpToken.balanceOf(address(this)); pool.lpToken.safeTransferFrom(_msgSender(), address(this), _amount); uint256 receivedAmount = pool.lpToken.balanceOf(address(this)).sub(balanceBefore); _updateUserAndPool(user, pool, receivedAmount, true); IRewarder _rewarder = pool.rewarder; if (address(_rewarder) != address(0)) { _rewarder.onNETTReward(_msgSender(), user.amount); } emit Deposit(_msgSender(), _pid, receivedAmount); } /// @notice Withdraw LP tokens from BNTF /// @param _pid The index of the pool. See `poolInfo` /// @param _amount LP token amount to withdraw function withdraw(uint256 _pid, uint256 _amount) external nonReentrant { harvestFromNETTFarm(); updatePool(_pid); PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_msgSender()]; require(user.amount >= _amount, "BoostedNETTFarm: withdraw not good"); if (user.amount != 0) { _harvestNETT(user, pool, _pid); } _updateUserAndPool(user, pool, _amount, false); pool.lpToken.safeTransfer(_msgSender(), _amount); IRewarder _rewarder = pool.rewarder; if (address(_rewarder) != address(0)) { _rewarder.onNETTReward(_msgSender(), user.amount); } emit Withdraw(_msgSender(), _pid, _amount); } /// @notice Updates factor after after a veNETT token operation. /// This function needs to be called by the veNETT contract after /// every mint / burn. /// @param _user The users address we are updating /// @param _newVeNETTBalance The new balance of the users veNETT function updateFactor(address _user, uint256 _newVeNETTBalance) external { require(_msgSender() == address(VENETT), "BoostedNETTFarm: Caller not veNETT"); uint256 len = poolInfo.length; uint256 _ACC_TOKEN_PRECISION = ACC_TOKEN_PRECISION; for (uint256 pid; pid < len; ++pid) { UserInfo storage user = userInfo[pid][_user]; // Skip if user doesn't have any deposit in the pool uint256 amount = user.amount; if (amount == 0) { continue; } PoolInfo storage pool = poolInfo[pid]; updatePool(pid); uint256 oldFactor = user.factor; (uint256 accNETTPerShare, uint256 accNETTPerFactorPerShare) = ( pool.accNETTPerShare, pool.accNETTPerFactorPerShare ); uint256 pending = amount .mul(accNETTPerShare) .add(oldFactor.mul(accNETTPerFactorPerShare)) .div(_ACC_TOKEN_PRECISION) .sub(user.rewardDebt); // Increase claimableNETT claimableNETT[pid][_user] = claimableNETT[pid][_user].add(pending); // Update users veNETTBalance uint256 newFactor = _getUserFactor(amount, _newVeNETTBalance); user.factor = newFactor; pool.totalFactor = pool.totalFactor.add(newFactor).sub(oldFactor); user.rewardDebt = amount.mul(accNETTPerShare).add(newFactor.mul(accNETTPerFactorPerShare)).div( _ACC_TOKEN_PRECISION ); } } /// @notice Withdraw without caring about rewards (EMERGENCY ONLY) /// @param _pid The index of the pool. See `poolInfo` function emergencyWithdraw(uint256 _pid) external nonReentrant { PoolInfo storage pool = poolInfo[_pid]; UserInfo storage user = userInfo[_pid][_msgSender()]; pool.totalFactor = pool.totalFactor.sub(user.factor); pool.totalLpSupply = pool.totalLpSupply.sub(user.amount); uint256 amount = user.amount; user.amount = 0; user.rewardDebt = 0; user.factor = 0; IRewarder _rewarder = pool.rewarder; if (address(_rewarder) != address(0)) { _rewarder.onNETTReward(_msgSender(), 0); } // Note: transfer can fail or succeed if `amount` is zero pool.lpToken.safeTransfer(_msgSender(), amount); emit EmergencyWithdraw(_msgSender(), _pid, amount); } /// @notice Calculates and returns the `amount` of NETT per second /// @return amount The amount of NETT emitted per second function nettPerSec() public view returns (uint256 amount) { amount = NETTFarm.nettPerSec().mul(NETTFarm.poolInfo(MASTER_PID).allocPoint).div(NETTFarm.totalAllocPoint()); } /// @notice View function to see pending NETT on frontend /// @param _pid The index of the pool. See `poolInfo` /// @param _user Address of user /// @return pendingNETT NETT reward for a given user. /// @return bonusTokenAddress The address of the bonus reward. /// @return bonusTokenSymbol The symbol of the bonus token. /// @return pendingBonusToken The amount of bonus rewards pending. function pendingTokens(uint256 _pid, address _user) external view returns ( uint256 pendingNETT, address bonusTokenAddress, string memory bonusTokenSymbol, uint256 pendingBonusToken ) { PoolInfo memory pool = poolInfo[_pid]; UserInfo memory user = userInfo[_pid][_user]; uint256 accNETTPerShare = pool.accNETTPerShare; uint256 accNETTPerFactorPerShare = pool.accNETTPerFactorPerShare; if (block.timestamp > pool.lastRewardTimestamp && pool.totalLpSupply != 0 && pool.allocPoint != 0) { uint256 secondsElapsed = block.timestamp - pool.lastRewardTimestamp; uint256 nettReward = secondsElapsed.mul(nettPerSec()).mul(pool.allocPoint).div(totalAllocPoint); accNETTPerShare = accNETTPerShare.add( nettReward.mul(ACC_TOKEN_PRECISION).mul(10_000 - pool.veNETTShareBp).div(pool.totalLpSupply.mul(10_000)) ); if (pool.veNETTShareBp != 0 && pool.totalFactor != 0) { accNETTPerFactorPerShare = accNETTPerFactorPerShare.add( nettReward.mul(ACC_TOKEN_PRECISION).mul(pool.veNETTShareBp).div(pool.totalFactor.mul(10_000)) ); } } pendingNETT = (user.amount.mul(accNETTPerShare)) .add(user.factor.mul(accNETTPerFactorPerShare)) .div(ACC_TOKEN_PRECISION) .add(claimableNETT[_pid][_user]) .sub(user.rewardDebt); // If it's a double reward farm, we return info about the bonus token if (address(pool.rewarder) != address(0)) { bonusTokenAddress = address(pool.rewarder.rewardToken()); bonusTokenSymbol = IERC20(bonusTokenAddress).safeSymbol(); pendingBonusToken = pool.rewarder.pendingTokens(_user); } } /// @notice Returns the number of BNTF pools. /// @return pools The amount of pools in this farm function poolLength() external view returns (uint256 pools) { pools = poolInfo.length; } /// @notice Update reward variables for all pools. Be careful of gas spending! function massUpdatePools() public { uint256 len = poolInfo.length; for (uint256 i = 0; i < len; ++i) { updatePool(i); } } /// @notice Update reward variables of the given pool /// @param _pid The index of the pool. See `poolInfo` function updatePool(uint256 _pid) public { PoolInfo storage pool = poolInfo[_pid]; uint256 lastRewardTimestamp = pool.lastRewardTimestamp; if (block.timestamp > lastRewardTimestamp) { uint256 lpSupply = pool.totalLpSupply; uint256 allocPoint = pool.allocPoint; // gas opt and prevent div by 0 if (lpSupply != 0 && allocPoint != 0) { uint256 secondsElapsed = block.timestamp - lastRewardTimestamp; uint256 veNETTShareBp = pool.veNETTShareBp; uint256 totalFactor = pool.totalFactor; uint256 nettReward = secondsElapsed.mul(nettPerSec()).mul(allocPoint).div(totalAllocPoint); pool.accNETTPerShare = pool.accNETTPerShare.add( nettReward.mul(ACC_TOKEN_PRECISION).mul(10_000 - veNETTShareBp).div(lpSupply.mul(10_000)) ); // If veNETTShareBp is 0, then we don't need to update it if (veNETTShareBp != 0 && totalFactor != 0) { pool.accNETTPerFactorPerShare = pool.accNETTPerFactorPerShare.add( nettReward.mul(ACC_TOKEN_PRECISION).mul(veNETTShareBp).div(totalFactor.mul(10_000)) ); } } pool.lastRewardTimestamp = uint64(block.timestamp);emit UpdatePool( _pid, pool.lastRewardTimestamp, lpSupply, pool.accNETTPerShare, pool.accNETTPerFactorPerShare ); } } /// @notice Harvests NETT from `NETTFarm` NTF and pool `MASTER_PID` to this BNTF contract function harvestFromNETTFarm() public { NETTFarm.deposit(MASTER_PID, 0); } /// @notice Return an user's factor /// @param amount The user's amount of liquidity /// @param veNETTBalance The user's veNETT balance /// @return uint256 The user's factor function _getUserFactor(uint256 amount, uint256 veNETTBalance) private pure returns (uint256) { return Math.sqrt(amount * veNETTBalance); } /// @notice Updates user and pool infos /// @param _user The user that needs to be updated /// @param _pool The pool that needs to be updated /// @param _amount The amount that was deposited or withdrawn /// @param _isDeposit If the action of the user is a deposit function _updateUserAndPool( UserInfo storage _user, PoolInfo storage _pool, uint256 _amount, bool _isDeposit ) private { uint256 oldAmount = _user.amount; uint256 newAmount = _isDeposit ? oldAmount.add(_amount) : oldAmount.sub(_amount); if (_amount != 0) { _user.amount = newAmount; _pool.totalLpSupply = _isDeposit ? _pool.totalLpSupply.add(_amount) : _pool.totalLpSupply.sub(_amount); } uint256 oldFactor = _user.factor; uint256 newFactor = _getUserFactor(newAmount, VENETT.balanceOf(_msgSender())); if (oldFactor != newFactor) { _user.factor = newFactor; _pool.totalFactor = _pool.totalFactor.add(newFactor).sub(oldFactor); } _user.rewardDebt = newAmount.mul(_pool.accNETTPerShare).add(newFactor.mul(_pool.accNETTPerFactorPerShare)).div( ACC_TOKEN_PRECISION ); } /// @notice Harvests user's pending NETT /// @dev WARNING this function doesn't update user's rewardDebt, /// it still needs to be updated in order for this contract to work properlly /// @param _user The user that will harvest its rewards /// @param _pool The pool where the user staked and want to harvest its NETT /// @param _pid The pid of that pool function _harvestNETT( UserInfo storage _user, PoolInfo storage _pool, uint256 _pid ) private { uint256 pending = (_user.amount.mul(_pool.accNETTPerShare)) .add(_user.factor.mul(_pool.accNETTPerFactorPerShare)) .div(ACC_TOKEN_PRECISION) .add(claimableNETT[_pid][_msgSender()]) .sub(_user.rewardDebt); claimableNETT[_pid][_msgSender()] = 0; if (pending != 0) { NETT.safeTransfer(_msgSender(), pending); emit Harvest(_msgSender(), _pid, pending); } } }
contracts/interfaces/IERC20.sol
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); // EIP 2612 function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; }
@openzeppelin/contracts-upgradeable/GSN/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../proxy/Initializable.sol"; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } uint256[50] private __gap; }
@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../GSN/ContextUpgradeable.sol"; import "../proxy/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } uint256[49] private __gap; }
@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMathUpgradeable { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
@openzeppelin/contracts-upgradeable/proxy/Initializable.sol
// SPDX-License-Identifier: MIT // solhint-disable-next-line compiler-version pragma solidity >=0.4.24 <0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {UpgradeableProxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || _isConstructor() || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function _isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; // solhint-disable-next-line no-inline-assembly assembly { cs := extcodesize(self) } return cs == 0; } }
@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0 <0.8.0; import "../proxy/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal initializer { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal initializer { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } uint256[49] private __gap; }
contracts/interfaces/INETTFarm.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.6.12; pragma experimental ABIEncoderV2; import "../libs/BoringNETTERC20.sol"; interface INETTFarm { using BoringNETTERC20 for IERC20; struct UserInfo { uint256 amount; // How many LP tokens the user has provided. uint256 rewardDebt; // Reward debt. See explanation below. } struct PoolInfo { IERC20 lpToken; // Address of LP token contract. uint256 allocPoint; // How many allocation points assigned to this pool. NETT to distribute per block. uint256 lastRewardTimestamp; // Last block number that NETT distribution occurs. uint256 accNETTPerShare; // Accumulated NETT per share, times 1e12. See below. } function userInfo(uint256 _pid, address _user) external view returns (INETTFarm.UserInfo memory); function poolInfo(uint256 pid) external view returns (INETTFarm.PoolInfo memory); function totalAllocPoint() external view returns (uint256); function nettPerSec() external view returns (uint256); function deposit(uint256 _pid, uint256 _amount) external; }
contracts/interfaces/IRewarder.sol
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "./IERC20.sol"; interface IRewarder { function onNETTReward(address user, uint256 newLpAmount) external; function pendingTokens(address user) external view returns (uint256 pending); function rewardToken() external view returns (IERC20); }
contracts/libs/BoringNETTERC20.sol
// SPDX-License-Identifier: MIT pragma solidity 0.6.12; import "../interfaces/IERC20.sol"; // solhint-disable avoid-low-level-calls library BoringNETTERC20 { bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol() bytes4 private constant SIG_NAME = 0x06fdde03; // name() bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals() bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256) bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256) function returnDataToString(bytes memory data) internal pure returns (string memory) { if (data.length >= 64) { return abi.decode(data, (string)); } else if (data.length == 32) { uint8 i = 0; while (i < 32 && data[i] != 0) { i++; } bytes memory bytesArray = new bytes(i); for (i = 0; i < 32 && data[i] != 0; i++) { bytesArray[i] = data[i]; } return string(bytesArray); } else { return "???"; } } /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string. /// @param token The address of the ERC-20 token contract. /// @return (string) Token symbol. function safeSymbol(IERC20 token) internal view returns (string memory) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL)); return success ? returnDataToString(data) : "???"; } /// @notice Provides a safe ERC20.name version which returns '???' as fallback string. /// @param token The address of the ERC-20 token contract. /// @return (string) Token name. function safeName(IERC20 token) internal view returns (string memory) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME)); return success ? returnDataToString(data) : "???"; } /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value. /// @param token The address of the ERC-20 token contract. /// @return (uint8) Token decimals. function safeDecimals(IERC20 token) internal view returns (uint8) { (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS)); return success && data.length == 32 ? abi.decode(data, (uint8)) : 18; } /// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations. /// Reverts on a failed transfer. /// @param token The address of the ERC-20 token. /// @param to Transfer tokens to. /// @param amount The token amount. function safeTransfer( IERC20 token, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER, to, amount)); require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: Transfer failed"); } /// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations. /// Reverts on a failed transfer. /// @param token The address of the ERC-20 token. /// @param from Transfer tokens from. /// @param to Transfer tokens to. /// @param amount The token amount. function safeTransferFrom( IERC20 token, address from, address to, uint256 amount ) internal { (bool success, bytes memory data) = address(token).call( abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount) ); require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: TransferFrom failed"); } }
contracts/libs/Math.sol
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.6.12; // a library for performing various math operations library Math { function min(uint256 x, uint256 y) internal pure returns (uint256 z) { z = x < y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }
Contract ABI
[{"type":"event","name":"Add","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"allocPoint","internalType":"uint256","indexed":false},{"type":"uint256","name":"veNETTShareBp","internalType":"uint256","indexed":false},{"type":"address","name":"lpToken","internalType":"contract IERC20","indexed":true},{"type":"address","name":"rewarder","internalType":"contract IRewarder","indexed":true}],"anonymous":false},{"type":"event","name":"Deposit","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EmergencyWithdraw","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Harvest","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Init","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Set","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"allocPoint","internalType":"uint256","indexed":false},{"type":"uint256","name":"veNETTShareBp","internalType":"uint256","indexed":false},{"type":"address","name":"rewarder","internalType":"contract IRewarder","indexed":true},{"type":"bool","name":"overwrite","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"UpdatePool","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"lastRewardTimestamp","internalType":"uint256","indexed":false},{"type":"uint256","name":"lpSupply","internalType":"uint256","indexed":false},{"type":"uint256","name":"accNETTPerShare","internalType":"uint256","indexed":false},{"type":"uint256","name":"accNETTPerFactorPerShare","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdraw","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MASTER_PID","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"NETT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract INETTFarm"}],"name":"NETTFarm","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"VENETT","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"add","inputs":[{"type":"uint96","name":"_allocPoint","internalType":"uint96"},{"type":"uint32","name":"_veNETTShareBp","internalType":"uint32"},{"type":"address","name":"_lpToken","internalType":"contract IERC20"},{"type":"address","name":"_rewarder","internalType":"contract IRewarder"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"claimableNETT","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deposit","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyWithdraw","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"harvestFromNETTFarm","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"init","inputs":[{"type":"address","name":"_dummyToken","internalType":"contract IERC20"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_NETTFarm","internalType":"contract INETTFarm"},{"type":"address","name":"_nett","internalType":"contract IERC20"},{"type":"address","name":"_veNETT","internalType":"contract IERC20"},{"type":"uint256","name":"_MASTER_PID","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"massUpdatePools","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"}],"name":"nettPerSec","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"pendingNETT","internalType":"uint256"},{"type":"address","name":"bonusTokenAddress","internalType":"address"},{"type":"string","name":"bonusTokenSymbol","internalType":"string"},{"type":"uint256","name":"pendingBonusToken","internalType":"uint256"}],"name":"pendingTokens","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"lpToken","internalType":"contract IERC20"},{"type":"uint96","name":"allocPoint","internalType":"uint96"},{"type":"uint256","name":"accNETTPerShare","internalType":"uint256"},{"type":"uint256","name":"accNETTPerFactorPerShare","internalType":"uint256"},{"type":"uint64","name":"lastRewardTimestamp","internalType":"uint64"},{"type":"address","name":"rewarder","internalType":"contract IRewarder"},{"type":"uint32","name":"veNETTShareBp","internalType":"uint32"},{"type":"uint256","name":"totalFactor","internalType":"uint256"},{"type":"uint256","name":"totalLpSupply","internalType":"uint256"}],"name":"poolInfo","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"pools","internalType":"uint256"}],"name":"poolLength","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint96","name":"_allocPoint","internalType":"uint96"},{"type":"uint32","name":"_veNETTShareBp","internalType":"uint32"},{"type":"address","name":"_rewarder","internalType":"contract IRewarder"},{"type":"bool","name":"_overwrite","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalAllocPoint","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateFactor","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"uint256","name":"_newVeNETTBalance","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePool","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"rewardDebt","internalType":"uint256"},{"type":"uint256","name":"factor","internalType":"uint256"}],"name":"userInfo","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_amount","internalType":"uint256"}]}]
Contract Creation Code
0x608060405234801561001057600080fd5b50613867806100206000396000f3fe608060405234801561001057600080fd5b50600436106101a35760003560e01c8063630b5ba1116100ee578063b7faab8a11610097578063f0d234c811610071578063f0d234c814610312578063f2fde38b1461031a578063f3cd74501461032d578063ffcd426314610340576101a3565b8063b7faab8a146102e4578063cf756fdf146102ec578063e2bbb158146102ff576101a3565b80638da5cb5b116100c85780638da5cb5b146102a757806393f1a40b146102af578063980e5f90146102d1576101a3565b8063630b5ba11461028f578063715018a614610297578063782acc271461029f576101a3565b8063441a3e70116101505780635312ea8e1161012a5780635312ea8e14610261578063561be05a1461027457806361621aaa14610287576101a3565b8063441a3e70146102285780634f00a93e1461023b57806351eb05a61461024e576101a3565b806319ab453c1161018157806319ab453c146101f65780632efc61111461020b5780633390bb6914610220576101a3565b8063081e3eda146101a85780631526fe27146101c657806317caf6f1146101ee575b600080fd5b6101b0610363565b6040516101bd91906136dc565b60405180910390f35b6101d96101d4366004612fd7565b610369565b6040516101bd999897969594939291906131cc565b6101b061041f565b610209610204366004612e0c565b610425565b005b610213610735565b6040516101bd919061317b565b6101b0610744565b610209610236366004613036565b610907565b610209610249366004612e28565b610af3565b61020961025c366004612fd7565b610ccb565b61020961026f366004612fd7565b610ebc565b6102096102823660046130bc565b61106e565b6101b0611495565b61020961149b565b6102096114be565b610213611555565b610213611564565b6102c26102bd366004613007565b611573565b6040516101bd9392919061372c565b6102096102df366004613057565b61159f565b61020961182c565b6102096102fa366004612e8b565b6118ad565b61020961030d366004613036565b6119a1565b610213611ca2565b610209610328366004612e0c565b611cb1565b6101b061033b366004613007565b611d80565b61035361034e366004613007565b611d9d565b6040516101bd94939291906136e5565b609b5490565b609b818154811061037657fe5b60009182526020909120600690910201805460018201546002830154600384015460048501546005909501546001600160a01b038086169750740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16959394929367ffffffffffffffff83169368010000000000000000840416927c0100000000000000000000000000000000000000000000000000000000900463ffffffff169189565b609e5481565b61042d6121dc565b6033546001600160a01b039081169116146104635760405162461bcd60e51b815260040161045a906134ed565b60405180910390fd5b6097546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b03838116926370a08231926104ae929091169060040161317b565b60206040518083038186803b1580156104c657600080fd5b505afa1580156104da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fe9190612fef565b1561051b5760405162461bcd60e51b815260040161045a906135b6565b6000816001600160a01b03166370a082316105346121dc565b6040518263ffffffff1660e01b8152600401610550919061317b565b60206040518083038186803b15801561056857600080fd5b505afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a09190612fef565b9050806105bf5760405162461bcd60e51b815260040161045a90613648565b6105dc6105ca6121dc565b6001600160a01b0384169030846121e0565b6097546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038481169263095ea7b3926106299290911690859060040161318f565b602060405180830381600087803b15801561064357600080fd5b505af1158015610657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067b9190612e53565b50609754609a546040517fe2bbb1580000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163e2bbb158916106c891859060040161371e565b600060405180830381600087803b1580156106e257600080fd5b505af11580156106f6573d6000803e3d6000fd5b505050507f387d06ac3b54c0ade104e08db87887286d162da416d27a605fc64e4f26c013388160405161072991906136dc565b60405180910390a15050565b6098546001600160a01b031681565b6000610902609760009054906101000a90046001600160a01b03166001600160a01b03166317caf6f16040518163ffffffff1660e01b815260040160206040518083038186803b15801561079757600080fd5b505afa1580156107ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107cf9190612fef565b609754609a546040517f1526fe270000000000000000000000000000000000000000000000000000000081526108fc926001600160a01b031691631526fe279161081c91906004016136dc565b60806040518083038186803b15801561083457600080fd5b505afa158015610848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086c9190612f85565b60200151609760009054906101000a90046001600160a01b03166001600160a01b0316633390bb696040518163ffffffff1660e01b815260040160206040518083038186803b1580156108be57600080fd5b505afa1580156108d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f69190612fef565b90612324565b90612367565b905090565b6002606554141561092a5760405162461bcd60e51b815260040161045a906136a5565b600260655561093761182c565b61094082610ccb565b6000609b838154811061094f57fe5b60009182526020808320868452609d909152604083206006909202019250816109766121dc565b6001600160a01b03166001600160a01b03168152602001908152602001600020905082816000015410156109bc5760405162461bcd60e51b815260040161045a90613251565b8054156109ce576109ce8183866123a9565b6109db81838560006124cc565b6109f86109e66121dc565b83546001600160a01b0316908561262c565b60038201546801000000000000000090046001600160a01b03168015610a9e57806001600160a01b03166341197d4d610a2f6121dc565b84546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152610a6b92919060040161318f565b600060405180830381600087803b158015610a8557600080fd5b505af1158015610a99573d6000803e3d6000fd5b505050505b84610aa76121dc565b6001600160a01b03167ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56886604051610adf91906136dc565b60405180910390a350506001606555505050565b6099546001600160a01b0316610b076121dc565b6001600160a01b031614610b2d5760405162461bcd60e51b815260040161045a906132ae565b609b54609f5460005b82811015610cc4576000818152609d602090815260408083206001600160a01b03891684529091529020805480610b6e575050610cbc565b6000609b8481548110610b7d57fe5b90600052602060002090600602019050610b9684610ccb565b6002808401546001808401549284015490860154919291600090610bdb90610bd58b6108fc610bc58988612324565b610bcf8c8a612324565b90612766565b9061278b565b9050610c268160a060008b815260200190815260200160002060008f6001600160a01b03166001600160a01b031681526020019081526020016000205461276690919063ffffffff16565b60a060008a815260200190815260200160002060008e6001600160a01b03166001600160a01b03168152602001908152602001600020819055506000610c6c878d6127cd565b600289018190556004870154909150610c8b908690610bd59084612766565b6004870155610cab8a6108fc610ca18487612324565b610bcf8b89612324565b886001018190555050505050505050505b600101610b36565b5050505050565b6000609b8281548110610cda57fe5b60009182526020909120600690910201600381015490915067ffffffffffffffff1642811015610eb757600582015482547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff168115801590610d3f57508015155b15610e305760038401546004850154609e5442869003927c0100000000000000000000000000000000000000000000000000000000900463ffffffff169190600090610d9b906108fc876108f6610d94610744565b8990612324565b9050610dd7610dcc610daf88612710612324565b6108fc86612710036108f6609f548761232490919063ffffffff16565b60018a015490612766565b60018901558215801590610dea57508115155b15610e2b57610e25610e1a610e0184612710612324565b6108fc866108f6609f548761232490919063ffffffff16565b60028a015490612766565b60028901555b505050505b6003840180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000164267ffffffffffffffff90811691909117918290556001860154600287015460405189947f3a15998b7576ed92447b3dd03767c4977c339833be8a90fc16caa7653db12e6e94610eac949116928892613742565b60405180910390a250505b505050565b60026065541415610edf5760405162461bcd60e51b815260040161045a906136a5565b60026065819055506000609b8281548110610ef657fe5b60009182526020808320858452609d90915260408320600690920201925081610f1d6121dc565b6001600160a01b03166001600160a01b031681526020019081526020016000209050610f5a8160020154836004015461278b90919063ffffffff16565b600483015580546005830154610f6f9161278b565b60058301558054600080835560018301819055600283015560038301546801000000000000000090046001600160a01b0316801561101057806001600160a01b03166341197d4d610fbe6121dc565b60006040518363ffffffff1660e01b8152600401610fdd92919061318f565b600060405180830381600087803b158015610ff757600080fd5b505af115801561100b573d6000803e3d6000fd5b505050505b61102d61101b6121dc565b85546001600160a01b0316908461262c565b846110366121dc565b6001600160a01b03167fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae059584604051610adf91906136dc565b6110766121dc565b6033546001600160a01b039081169116146110a35760405162461bcd60e51b815260040161045a906134ed565b6001600160a01b0382166000908152609c602052604090205460ff16156110dc5760405162461bcd60e51b815260040161045a90613433565b6127108363ffffffff1611156111045760405162461bcd60e51b815260040161045a90613522565b609b54603210156111275760405162461bcd60e51b815260040161045a9061357f565b6001600160a01b0382166000818152609c602052604090819020805460ff19166001179055517f70a082310000000000000000000000000000000000000000000000000000000081526370a082319061118490309060040161317b565b60206040518083038186803b15801561119c57600080fd5b505afa1580156111b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d49190612fef565b506001600160a01b0381161561125f576040517f41197d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b038216906341197d4d9061122c90600090819060040161318f565b600060405180830381600087803b15801561124657600080fd5b505af115801561125a573d6000803e3d6000fd5b505050505b61126761149b565b609e54611282906bffffffffffffffffffffffff8616612766565b609e81905550609b604051806101200160405280846001600160a01b03168152602001866bffffffffffffffffffffffff16815260200160008152602001600081526020014267ffffffffffffffff168152602001836001600160a01b031681526020018563ffffffff168152602001600081526020016000815250908060018154018082558091505060019003906000526020600020906006020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550604082015181600101556060820151816002015560808201518160030160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060a08201518160030160086101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c082015181600301601c6101000a81548163ffffffff021916908363ffffffff16021790555060e0820151816004015561010082015181600501555050806001600160a01b0316826001600160a01b03166001609b80549050037ffa7db60584eedcec543415482c572116ee7545102bc1e1ca9e5219ff0ea3be328787604051611487929190613769565b60405180910390a450505050565b609a5481565b609b5460005b818110156114ba576114b281610ccb565b6001016114a1565b5050565b6114c66121dc565b6033546001600160a01b039081169116146114f35760405162461bcd60e51b815260040161045a906134ed565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6099546001600160a01b031681565b6033546001600160a01b031690565b609d60209081526000928352604080842090915290825290208054600182015460029092015490919083565b6115a76121dc565b6033546001600160a01b039081169116146115d45760405162461bcd60e51b815260040161045a906134ed565b6127108363ffffffff1611156115fc5760405162461bcd60e51b815260040161045a90613522565b61160461149b565b6000609b868154811061161357fe5b600091825260209091206006909102018054609e54919250611664916bffffffffffffffffffffffff74010000000000000000000000000000000000000000909204821691610bd591908916612766565b609e5580546001600160a01b0316740100000000000000000000000000000000000000006bffffffffffffffffffffffff8716021781556003810180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff87160217905581156117b9576001600160a01b03831615611778576040517f41197d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b038416906341197d4d9061174590600090819060040161318f565b600060405180830381600087803b15801561175f57600080fd5b505af1158015611773573d6000803e3d6000fd5b505050505b6003810180547fffffffff0000000000000000000000000000000000000000ffffffffffffffff16680100000000000000006001600160a01b038616021790555b816117dd5760038101546801000000000000000090046001600160a01b03166117df565b825b6001600160a01b0316867f0db1d9531544c4edebc3104fe894a7e82c00bd1b9a676053351b0d86d4ebbd4d87878660405161181c9392919061378d565b60405180910390a3505050505050565b609754609a546040517fe2bbb1580000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163e2bbb158916118799160009060040161371e565b600060405180830381600087803b15801561189357600080fd5b505af11580156118a7573d6000803e3d6000fd5b50505050565b600054610100900460ff16806118c657506118c66127da565b806118d4575060005460ff16155b6118f05760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff1615801561191b576000805460ff1961ff0019909116610100171660011790555b6119236127e0565b609780546001600160a01b038088167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609880548784169083161790556099805492861692909116919091179055609a829055670de0b6b3a7640000609f558015610cc4576000805461ff00191690555050505050565b600260655414156119c45760405162461bcd60e51b815260040161045a906136a5565b60026065556119d161182c565b6119da82610ccb565b6000609b83815481106119e957fe5b60009182526020808320868452609d90915260408320600690920201925081611a106121dc565b6001600160a01b031681526020810191909152604001600020805490915015611a3e57611a3e8183866123a9565b81546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a0823190611a8790309060040161317b565b60206040518083038186803b158015611a9f57600080fd5b505afa158015611ab3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad79190612fef565b9050611af7611ae46121dc565b84546001600160a01b03169030876121e0565b82546040517f70a08231000000000000000000000000000000000000000000000000000000008152600091611b969184916001600160a01b0316906370a0823190611b4690309060040161317b565b60206040518083038186803b158015611b5e57600080fd5b505afa158015611b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd59190612fef565b9050611ba583858360016124cc565b60038401546801000000000000000090046001600160a01b03168015611c4b57806001600160a01b03166341197d4d611bdc6121dc565b86546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152611c1892919060040161318f565b600060405180830381600087803b158015611c3257600080fd5b505af1158015611c46573d6000803e3d6000fd5b505050505b86611c546121dc565b6001600160a01b03167f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1584604051611c8c91906136dc565b60405180910390a3505060016065555050505050565b6097546001600160a01b031681565b611cb96121dc565b6033546001600160a01b03908116911614611ce65760405162461bcd60e51b815260040161045a906134ed565b6001600160a01b038116611d0c5760405162461bcd60e51b815260040161045a90613342565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60a060209081526000928352604080842090915290825290205481565b60008060606000611dac612d6f565b609b8781548110611db957fe5b6000918252602091829020604080516101208101825260069390930290910180546001600160a01b038082168552740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169484019490945260018101549183019190915260028101546060830152600381015467ffffffffffffffff8116608084015268010000000000000000810490931660a08301527c010000000000000000000000000000000000000000000000000000000090920463ffffffff1660c0820152600482015460e08201526005909101546101008201529050611ea0612dbb565b506000878152609d602090815260408083206001600160a01b038a16845282529182902082516060808201855282548252600183015493820193909352600290910154818401529183015190830151608084015167ffffffffffffffff1642118015611f10575061010084015115155b8015611f2d575060208401516bffffffffffffffffffffffff1615155b1561203b576000846080015167ffffffffffffffff16420390506000611f77609e546108fc88602001516bffffffffffffffffffffffff166108f6611f70610744565b8790612324565b9050611fc7611fc0611f9961271089610100015161232490919063ffffffff16565b6108fc8960c001516127100363ffffffff166108f6609f548761232490919063ffffffff16565b8590612766565b93508560c0015163ffffffff16600014158015611fe7575060e086015115155b156120385761203561202e61200b6127108960e0015161232490919063ffffffff16565b6108fc8960c0015163ffffffff166108f6609f548761232490919063ffffffff16565b8490612766565b92505b50505b60208084015160008c815260a0835260408082206001600160a01b038e16835290935282902054609f549286015161209193610bd59291610bcf91906108fc906120859089612324565b8a51610bcf908b612324565b60a08501519098506001600160a01b0316156121cf578360a001516001600160a01b031663f7c618c16040518163ffffffff1660e01b815260040160206040518083038186803b1580156120e457600080fd5b505afa1580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190612e6f565b9650612130876001600160a01b0316612873565b60a08501516040517fc031a66f0000000000000000000000000000000000000000000000000000000081529197506001600160a01b03169063c031a66f9061217c908c9060040161317b565b60206040518083038186803b15801561219457600080fd5b505afa1580156121a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cc9190612fef565b94505b5050505092959194509250565b3390565b60006060856001600160a01b03166323b872dd60e01b86868660405160240161220b939291906131a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051612294919061315f565b6000604051808303816000865af19150503d80600081146122d1576040519150601f19603f3d011682016040523d82523d6000602084013e6122d6565b606091505b50915091508180156123005750805115806123005750808060200190518101906123009190612e53565b61231c5760405162461bcd60e51b815260040161045a90613613565b505050505050565b60008261233357506000612361565b8282028284828161234057fe5b041461235e5760405162461bcd60e51b815260040161045a90613490565b90505b92915050565b600061235e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612980565b6001830154600082815260a060205260408120909161242491610bd590846123cf6121dc565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610bcf609f546108fc6124148a600201548c6002015461232490919063ffffffff16565b60018b01548c54610bcf91612324565b600083815260a060205260408120919250908161243f6121dc565b6001600160a01b0316815260208101919091526040016000205580156118a75761247d61246a6121dc565b6098546001600160a01b0316908361262c565b816124866121dc565b6001600160a01b03167f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae0660924954836040516124be91906136dc565b60405180910390a350505050565b83546000826124e4576124df828561278b565b6124ee565b6124ee8285612766565b90508315612527578086558261251257600585015461250d908561278b565b612521565b60058501546125219085612766565b60058601555b60028601546099546000906125bf9084906001600160a01b03166370a0823161254e6121dc565b6040518263ffffffff1660e01b815260040161256a919061317b565b60206040518083038186803b15801561258257600080fd5b505afa158015612596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ba9190612fef565b6127cd565b90508082146125ea576002880181905560048701546125e4908390610bd59084612766565b60048801555b61261a609f546108fc61260a8a600201548561232490919063ffffffff16565b60018b0154610bcf908890612324565b88600101819055505050505050505050565b60006060846001600160a01b031663a9059cbb60e01b858560405160240161265592919061318f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516126de919061315f565b6000604051808303816000865af19150503d806000811461271b576040519150601f19603f3d011682016040523d82523d6000602084013e612720565b606091505b509150915081801561274a57508051158061274a57508080602001905181019061274a9190612e53565b610cc45760405162461bcd60e51b815260040161045a9061330b565b60008282018381101561235e5760405162461bcd60e51b815260040161045a9061339f565b600061235e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129b7565b600061235e8284026129e3565b303b1590565b600054610100900460ff16806127f957506127f96127da565b80612807575060005460ff16155b6128235760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff1615801561284e576000805460ff1961ff0019909116610100171660011790555b612856612a34565b61285e612ab5565b8015612870576000805461ff00191690555b50565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009183916001600160a01b038616916128e8919061315f565b600060405180830381855afa9150503d8060008114612923576040519150601f19603f3d011682016040523d82523d6000602084013e612928565b606091505b50915091508161296d576040518060400160405280600381526020017f3f3f3f0000000000000000000000000000000000000000000000000000000000815250612976565b61297681612ba7565b925050505b919050565b600081836129a15760405162461bcd60e51b815260040161045a919061323e565b5060008385816129ad57fe5b0495945050505050565b600081848411156129db5760405162461bcd60e51b815260040161045a919061323e565b505050900390565b60006003821115612a26575080600160028204015b81811015612a2057809150600281828581612a0f57fe5b040181612a1857fe5b0490506129f8565b5061297b565b811561297b57506001919050565b600054610100900460ff1680612a4d5750612a4d6127da565b80612a5b575060005460ff16155b612a775760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff1615801561285e576000805460ff1961ff0019909116610100171660011790558015612870576000805461ff001916905550565b600054610100900460ff1680612ace5750612ace6127da565b80612adc575060005460ff16155b612af85760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff16158015612b23576000805460ff1961ff0019909116610100171660011790555b6000612b2d6121dc565b603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508015612870576000805461ff001916905550565b60606040825110612bcd5781806020019051810190612bc69190612edb565b905061297b565b815160201415612d355760005b60208160ff16108015612c215750828160ff1681518110612bf757fe5b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612c2e57600101612bda565b60608160ff1667ffffffffffffffff81118015612c4a57600080fd5b506040519080825280601f01601f191660200182016040528015612c75576020820181803683370190505b509050600091505b60208260ff16108015612cc45750838260ff1681518110612c9a57fe5b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612d2c57838260ff1681518110612cd857fe5b602001015160f81c60f81b818360ff1681518110612cf257fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190910190612c7d565b915061297b9050565b5060408051808201909152600381527f3f3f3f0000000000000000000000000000000000000000000000000000000000602082015261297b565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b60405180606001604052806000815260200160008152602001600081525090565b803563ffffffff8116811461236157600080fd5b80356bffffffffffffffffffffffff8116811461236157600080fd5b600060208284031215612e1d578081fd5b813561235e8161380e565b60008060408385031215612e3a578081fd5b8235612e458161380e565b946020939093013593505050565b600060208284031215612e64578081fd5b815161235e81613823565b600060208284031215612e80578081fd5b815161235e8161380e565b60008060008060808587031215612ea0578182fd5b8435612eab8161380e565b93506020850135612ebb8161380e565b92506040850135612ecb8161380e565b9396929550929360600135925050565b600060208284031215612eec578081fd5b815167ffffffffffffffff80821115612f03578283fd5b818401915084601f830112612f16578283fd5b815181811115612f24578384fd5b612f5560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016137bb565b9150808252856020828501011115612f6b578384fd5b612f7c8160208401602086016137e2565b50949350505050565b600060808284031215612f96578081fd5b612fa060806137bb565b8251612fab8161380e565b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b600060208284031215612fe8578081fd5b5035919050565b600060208284031215613000578081fd5b5051919050565b60008060408385031215613019578182fd5b82359150602083013561302b8161380e565b809150509250929050565b60008060408385031215613048578182fd5b50508035926020909101359150565b600080600080600060a0868803121561306e578081fd5b8535945061307f8760208801612df0565b935061308e8760408801612ddc565b9250606086013561309e8161380e565b915060808601356130ae81613823565b809150509295509295909350565b600080600080608085870312156130d1578182fd5b6130db8686612df0565b93506130ea8660208701612ddc565b925060408501356130fa8161380e565b9150606085013561310a8161380e565b939692955090935050565b6000815180845261312d8160208601602086016137e2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082516131718184602087016137e2565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03998a1681526bffffffffffffffffffffffff9890981660208901526040880196909652606087019490945267ffffffffffffffff92909216608086015290941660a084015263ffffffff90931660c083015260e08201929092526101008101919091526101200190565b60006020825261235e6020830184613115565b60208082526022908201527f426f6f737465644e4554544661726d3a207769746864726177206e6f7420676f60408201527f6f64000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526022908201527f426f6f737465644e4554544661726d3a2043616c6c6572206e6f742076654e4560408201527f5454000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f426f72696e6745524332303a205472616e73666572206661696c656400000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201527f6464726573730000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201527f647920696e697469616c697a6564000000000000000000000000000000000000606082015260800190565b60208082526021908201527f426f6f737465644e4554544661726d3a204c5020616c7265616479206164646560408201527f6400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252603b908201527f426f6f737465644e4554544661726d3a2076654e45545453686172654270206e60408201527f6565647320746f206265206c6f776572207468616e2031303030300000000000606082015260800190565b6020808252601f908201527f426f6f737465644e4554544661726d3a20546f6f206d616e7920706f6f6c7300604082015260600190565b60208082526035908201527f426f6f737465644e4554544661726d3a20416c7265616479206861732061206260408201527f616c616e6365206f662064756d6d7920746f6b656e0000000000000000000000606082015260800190565b6020808252818101527f426f72696e6745524332303a205472616e7366657246726f6d206661696c6564604082015260600190565b60208082526026908201527f426f6f737465644e4554544661726d3a2042616c616e6365206d75737420657860408201527f6365656420300000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b90815260200190565b60008582526001600160a01b03851660208301526080604083015261370d6080830185613115565b905082606083015295945050505050565b918252602082015260400190565b9283526020830191909152604082015260600190565b67ffffffffffffffff94909416845260208401929092526040830152606082015260800190565b6bffffffffffffffffffffffff92909216825263ffffffff16602082015260400190565b6bffffffffffffffffffffffff93909316835263ffffffff9190911660208301521515604082015260600190565b60405181810167ffffffffffffffff811182821017156137da57600080fd5b604052919050565b60005b838110156137fd5781810151838201526020016137e5565b838111156118a75750506000910152565b6001600160a01b038116811461287057600080fd5b801515811461287057600080fdfea2646970667358221220e18f5c3a4ecbf39c81769fe9ada92baddd9932dffa1e49830f6a6627674394b164736f6c634300060c0033
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101a35760003560e01c8063630b5ba1116100ee578063b7faab8a11610097578063f0d234c811610071578063f0d234c814610312578063f2fde38b1461031a578063f3cd74501461032d578063ffcd426314610340576101a3565b8063b7faab8a146102e4578063cf756fdf146102ec578063e2bbb158146102ff576101a3565b80638da5cb5b116100c85780638da5cb5b146102a757806393f1a40b146102af578063980e5f90146102d1576101a3565b8063630b5ba11461028f578063715018a614610297578063782acc271461029f576101a3565b8063441a3e70116101505780635312ea8e1161012a5780635312ea8e14610261578063561be05a1461027457806361621aaa14610287576101a3565b8063441a3e70146102285780634f00a93e1461023b57806351eb05a61461024e576101a3565b806319ab453c1161018157806319ab453c146101f65780632efc61111461020b5780633390bb6914610220576101a3565b8063081e3eda146101a85780631526fe27146101c657806317caf6f1146101ee575b600080fd5b6101b0610363565b6040516101bd91906136dc565b60405180910390f35b6101d96101d4366004612fd7565b610369565b6040516101bd999897969594939291906131cc565b6101b061041f565b610209610204366004612e0c565b610425565b005b610213610735565b6040516101bd919061317b565b6101b0610744565b610209610236366004613036565b610907565b610209610249366004612e28565b610af3565b61020961025c366004612fd7565b610ccb565b61020961026f366004612fd7565b610ebc565b6102096102823660046130bc565b61106e565b6101b0611495565b61020961149b565b6102096114be565b610213611555565b610213611564565b6102c26102bd366004613007565b611573565b6040516101bd9392919061372c565b6102096102df366004613057565b61159f565b61020961182c565b6102096102fa366004612e8b565b6118ad565b61020961030d366004613036565b6119a1565b610213611ca2565b610209610328366004612e0c565b611cb1565b6101b061033b366004613007565b611d80565b61035361034e366004613007565b611d9d565b6040516101bd94939291906136e5565b609b5490565b609b818154811061037657fe5b60009182526020909120600690910201805460018201546002830154600384015460048501546005909501546001600160a01b038086169750740100000000000000000000000000000000000000009095046bffffffffffffffffffffffff16959394929367ffffffffffffffff83169368010000000000000000840416927c0100000000000000000000000000000000000000000000000000000000900463ffffffff169189565b609e5481565b61042d6121dc565b6033546001600160a01b039081169116146104635760405162461bcd60e51b815260040161045a906134ed565b60405180910390fd5b6097546040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b03838116926370a08231926104ae929091169060040161317b565b60206040518083038186803b1580156104c657600080fd5b505afa1580156104da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104fe9190612fef565b1561051b5760405162461bcd60e51b815260040161045a906135b6565b6000816001600160a01b03166370a082316105346121dc565b6040518263ffffffff1660e01b8152600401610550919061317b565b60206040518083038186803b15801561056857600080fd5b505afa15801561057c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105a09190612fef565b9050806105bf5760405162461bcd60e51b815260040161045a90613648565b6105dc6105ca6121dc565b6001600160a01b0384169030846121e0565b6097546040517f095ea7b30000000000000000000000000000000000000000000000000000000081526001600160a01b038481169263095ea7b3926106299290911690859060040161318f565b602060405180830381600087803b15801561064357600080fd5b505af1158015610657573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061067b9190612e53565b50609754609a546040517fe2bbb1580000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163e2bbb158916106c891859060040161371e565b600060405180830381600087803b1580156106e257600080fd5b505af11580156106f6573d6000803e3d6000fd5b505050507f387d06ac3b54c0ade104e08db87887286d162da416d27a605fc64e4f26c013388160405161072991906136dc565b60405180910390a15050565b6098546001600160a01b031681565b6000610902609760009054906101000a90046001600160a01b03166001600160a01b03166317caf6f16040518163ffffffff1660e01b815260040160206040518083038186803b15801561079757600080fd5b505afa1580156107ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107cf9190612fef565b609754609a546040517f1526fe270000000000000000000000000000000000000000000000000000000081526108fc926001600160a01b031691631526fe279161081c91906004016136dc565b60806040518083038186803b15801561083457600080fd5b505afa158015610848573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086c9190612f85565b60200151609760009054906101000a90046001600160a01b03166001600160a01b0316633390bb696040518163ffffffff1660e01b815260040160206040518083038186803b1580156108be57600080fd5b505afa1580156108d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108f69190612fef565b90612324565b90612367565b905090565b6002606554141561092a5760405162461bcd60e51b815260040161045a906136a5565b600260655561093761182c565b61094082610ccb565b6000609b838154811061094f57fe5b60009182526020808320868452609d909152604083206006909202019250816109766121dc565b6001600160a01b03166001600160a01b03168152602001908152602001600020905082816000015410156109bc5760405162461bcd60e51b815260040161045a90613251565b8054156109ce576109ce8183866123a9565b6109db81838560006124cc565b6109f86109e66121dc565b83546001600160a01b0316908561262c565b60038201546801000000000000000090046001600160a01b03168015610a9e57806001600160a01b03166341197d4d610a2f6121dc565b84546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152610a6b92919060040161318f565b600060405180830381600087803b158015610a8557600080fd5b505af1158015610a99573d6000803e3d6000fd5b505050505b84610aa76121dc565b6001600160a01b03167ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b56886604051610adf91906136dc565b60405180910390a350506001606555505050565b6099546001600160a01b0316610b076121dc565b6001600160a01b031614610b2d5760405162461bcd60e51b815260040161045a906132ae565b609b54609f5460005b82811015610cc4576000818152609d602090815260408083206001600160a01b03891684529091529020805480610b6e575050610cbc565b6000609b8481548110610b7d57fe5b90600052602060002090600602019050610b9684610ccb565b6002808401546001808401549284015490860154919291600090610bdb90610bd58b6108fc610bc58988612324565b610bcf8c8a612324565b90612766565b9061278b565b9050610c268160a060008b815260200190815260200160002060008f6001600160a01b03166001600160a01b031681526020019081526020016000205461276690919063ffffffff16565b60a060008a815260200190815260200160002060008e6001600160a01b03166001600160a01b03168152602001908152602001600020819055506000610c6c878d6127cd565b600289018190556004870154909150610c8b908690610bd59084612766565b6004870155610cab8a6108fc610ca18487612324565b610bcf8b89612324565b886001018190555050505050505050505b600101610b36565b5050505050565b6000609b8281548110610cda57fe5b60009182526020909120600690910201600381015490915067ffffffffffffffff1642811015610eb757600582015482547401000000000000000000000000000000000000000090046bffffffffffffffffffffffff168115801590610d3f57508015155b15610e305760038401546004850154609e5442869003927c0100000000000000000000000000000000000000000000000000000000900463ffffffff169190600090610d9b906108fc876108f6610d94610744565b8990612324565b9050610dd7610dcc610daf88612710612324565b6108fc86612710036108f6609f548761232490919063ffffffff16565b60018a015490612766565b60018901558215801590610dea57508115155b15610e2b57610e25610e1a610e0184612710612324565b6108fc866108f6609f548761232490919063ffffffff16565b60028a015490612766565b60028901555b505050505b6003840180547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000164267ffffffffffffffff90811691909117918290556001860154600287015460405189947f3a15998b7576ed92447b3dd03767c4977c339833be8a90fc16caa7653db12e6e94610eac949116928892613742565b60405180910390a250505b505050565b60026065541415610edf5760405162461bcd60e51b815260040161045a906136a5565b60026065819055506000609b8281548110610ef657fe5b60009182526020808320858452609d90915260408320600690920201925081610f1d6121dc565b6001600160a01b03166001600160a01b031681526020019081526020016000209050610f5a8160020154836004015461278b90919063ffffffff16565b600483015580546005830154610f6f9161278b565b60058301558054600080835560018301819055600283015560038301546801000000000000000090046001600160a01b0316801561101057806001600160a01b03166341197d4d610fbe6121dc565b60006040518363ffffffff1660e01b8152600401610fdd92919061318f565b600060405180830381600087803b158015610ff757600080fd5b505af115801561100b573d6000803e3d6000fd5b505050505b61102d61101b6121dc565b85546001600160a01b0316908461262c565b846110366121dc565b6001600160a01b03167fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae059584604051610adf91906136dc565b6110766121dc565b6033546001600160a01b039081169116146110a35760405162461bcd60e51b815260040161045a906134ed565b6001600160a01b0382166000908152609c602052604090205460ff16156110dc5760405162461bcd60e51b815260040161045a90613433565b6127108363ffffffff1611156111045760405162461bcd60e51b815260040161045a90613522565b609b54603210156111275760405162461bcd60e51b815260040161045a9061357f565b6001600160a01b0382166000818152609c602052604090819020805460ff19166001179055517f70a082310000000000000000000000000000000000000000000000000000000081526370a082319061118490309060040161317b565b60206040518083038186803b15801561119c57600080fd5b505afa1580156111b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111d49190612fef565b506001600160a01b0381161561125f576040517f41197d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b038216906341197d4d9061122c90600090819060040161318f565b600060405180830381600087803b15801561124657600080fd5b505af115801561125a573d6000803e3d6000fd5b505050505b61126761149b565b609e54611282906bffffffffffffffffffffffff8616612766565b609e81905550609b604051806101200160405280846001600160a01b03168152602001866bffffffffffffffffffffffff16815260200160008152602001600081526020014267ffffffffffffffff168152602001836001600160a01b031681526020018563ffffffff168152602001600081526020016000815250908060018154018082558091505060019003906000526020600020906006020160009091909190915060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550604082015181600101556060820151816002015560808201518160030160006101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060a08201518160030160086101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c082015181600301601c6101000a81548163ffffffff021916908363ffffffff16021790555060e0820151816004015561010082015181600501555050806001600160a01b0316826001600160a01b03166001609b80549050037ffa7db60584eedcec543415482c572116ee7545102bc1e1ca9e5219ff0ea3be328787604051611487929190613769565b60405180910390a450505050565b609a5481565b609b5460005b818110156114ba576114b281610ccb565b6001016114a1565b5050565b6114c66121dc565b6033546001600160a01b039081169116146114f35760405162461bcd60e51b815260040161045a906134ed565b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b6099546001600160a01b031681565b6033546001600160a01b031690565b609d60209081526000928352604080842090915290825290208054600182015460029092015490919083565b6115a76121dc565b6033546001600160a01b039081169116146115d45760405162461bcd60e51b815260040161045a906134ed565b6127108363ffffffff1611156115fc5760405162461bcd60e51b815260040161045a90613522565b61160461149b565b6000609b868154811061161357fe5b600091825260209091206006909102018054609e54919250611664916bffffffffffffffffffffffff74010000000000000000000000000000000000000000909204821691610bd591908916612766565b609e5580546001600160a01b0316740100000000000000000000000000000000000000006bffffffffffffffffffffffff8716021781556003810180547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167c010000000000000000000000000000000000000000000000000000000063ffffffff87160217905581156117b9576001600160a01b03831615611778576040517f41197d4d0000000000000000000000000000000000000000000000000000000081526001600160a01b038416906341197d4d9061174590600090819060040161318f565b600060405180830381600087803b15801561175f57600080fd5b505af1158015611773573d6000803e3d6000fd5b505050505b6003810180547fffffffff0000000000000000000000000000000000000000ffffffffffffffff16680100000000000000006001600160a01b038616021790555b816117dd5760038101546801000000000000000090046001600160a01b03166117df565b825b6001600160a01b0316867f0db1d9531544c4edebc3104fe894a7e82c00bd1b9a676053351b0d86d4ebbd4d87878660405161181c9392919061378d565b60405180910390a3505050505050565b609754609a546040517fe2bbb1580000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163e2bbb158916118799160009060040161371e565b600060405180830381600087803b15801561189357600080fd5b505af11580156118a7573d6000803e3d6000fd5b50505050565b600054610100900460ff16806118c657506118c66127da565b806118d4575060005460ff16155b6118f05760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff1615801561191b576000805460ff1961ff0019909116610100171660011790555b6119236127e0565b609780546001600160a01b038088167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617909255609880548784169083161790556099805492861692909116919091179055609a829055670de0b6b3a7640000609f558015610cc4576000805461ff00191690555050505050565b600260655414156119c45760405162461bcd60e51b815260040161045a906136a5565b60026065556119d161182c565b6119da82610ccb565b6000609b83815481106119e957fe5b60009182526020808320868452609d90915260408320600690920201925081611a106121dc565b6001600160a01b031681526020810191909152604001600020805490915015611a3e57611a3e8183866123a9565b81546040517f70a082310000000000000000000000000000000000000000000000000000000081526000916001600160a01b0316906370a0823190611a8790309060040161317b565b60206040518083038186803b158015611a9f57600080fd5b505afa158015611ab3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ad79190612fef565b9050611af7611ae46121dc565b84546001600160a01b03169030876121e0565b82546040517f70a08231000000000000000000000000000000000000000000000000000000008152600091611b969184916001600160a01b0316906370a0823190611b4690309060040161317b565b60206040518083038186803b158015611b5e57600080fd5b505afa158015611b72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd59190612fef565b9050611ba583858360016124cc565b60038401546801000000000000000090046001600160a01b03168015611c4b57806001600160a01b03166341197d4d611bdc6121dc565b86546040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152611c1892919060040161318f565b600060405180830381600087803b158015611c3257600080fd5b505af1158015611c46573d6000803e3d6000fd5b505050505b86611c546121dc565b6001600160a01b03167f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a1584604051611c8c91906136dc565b60405180910390a3505060016065555050505050565b6097546001600160a01b031681565b611cb96121dc565b6033546001600160a01b03908116911614611ce65760405162461bcd60e51b815260040161045a906134ed565b6001600160a01b038116611d0c5760405162461bcd60e51b815260040161045a90613342565b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b60a060209081526000928352604080842090915290825290205481565b60008060606000611dac612d6f565b609b8781548110611db957fe5b6000918252602091829020604080516101208101825260069390930290910180546001600160a01b038082168552740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169484019490945260018101549183019190915260028101546060830152600381015467ffffffffffffffff8116608084015268010000000000000000810490931660a08301527c010000000000000000000000000000000000000000000000000000000090920463ffffffff1660c0820152600482015460e08201526005909101546101008201529050611ea0612dbb565b506000878152609d602090815260408083206001600160a01b038a16845282529182902082516060808201855282548252600183015493820193909352600290910154818401529183015190830151608084015167ffffffffffffffff1642118015611f10575061010084015115155b8015611f2d575060208401516bffffffffffffffffffffffff1615155b1561203b576000846080015167ffffffffffffffff16420390506000611f77609e546108fc88602001516bffffffffffffffffffffffff166108f6611f70610744565b8790612324565b9050611fc7611fc0611f9961271089610100015161232490919063ffffffff16565b6108fc8960c001516127100363ffffffff166108f6609f548761232490919063ffffffff16565b8590612766565b93508560c0015163ffffffff16600014158015611fe7575060e086015115155b156120385761203561202e61200b6127108960e0015161232490919063ffffffff16565b6108fc8960c0015163ffffffff166108f6609f548761232490919063ffffffff16565b8490612766565b92505b50505b60208084015160008c815260a0835260408082206001600160a01b038e16835290935282902054609f549286015161209193610bd59291610bcf91906108fc906120859089612324565b8a51610bcf908b612324565b60a08501519098506001600160a01b0316156121cf578360a001516001600160a01b031663f7c618c16040518163ffffffff1660e01b815260040160206040518083038186803b1580156120e457600080fd5b505afa1580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190612e6f565b9650612130876001600160a01b0316612873565b60a08501516040517fc031a66f0000000000000000000000000000000000000000000000000000000081529197506001600160a01b03169063c031a66f9061217c908c9060040161317b565b60206040518083038186803b15801561219457600080fd5b505afa1580156121a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cc9190612fef565b94505b5050505092959194509250565b3390565b60006060856001600160a01b03166323b872dd60e01b86868660405160240161220b939291906131a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909416939093179092529051612294919061315f565b6000604051808303816000865af19150503d80600081146122d1576040519150601f19603f3d011682016040523d82523d6000602084013e6122d6565b606091505b50915091508180156123005750805115806123005750808060200190518101906123009190612e53565b61231c5760405162461bcd60e51b815260040161045a90613613565b505050505050565b60008261233357506000612361565b8282028284828161234057fe5b041461235e5760405162461bcd60e51b815260040161045a90613490565b90505b92915050565b600061235e83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612980565b6001830154600082815260a060205260408120909161242491610bd590846123cf6121dc565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610bcf609f546108fc6124148a600201548c6002015461232490919063ffffffff16565b60018b01548c54610bcf91612324565b600083815260a060205260408120919250908161243f6121dc565b6001600160a01b0316815260208101919091526040016000205580156118a75761247d61246a6121dc565b6098546001600160a01b0316908361262c565b816124866121dc565b6001600160a01b03167f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae0660924954836040516124be91906136dc565b60405180910390a350505050565b83546000826124e4576124df828561278b565b6124ee565b6124ee8285612766565b90508315612527578086558261251257600585015461250d908561278b565b612521565b60058501546125219085612766565b60058601555b60028601546099546000906125bf9084906001600160a01b03166370a0823161254e6121dc565b6040518263ffffffff1660e01b815260040161256a919061317b565b60206040518083038186803b15801561258257600080fd5b505afa158015612596573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125ba9190612fef565b6127cd565b90508082146125ea576002880181905560048701546125e4908390610bd59084612766565b60048801555b61261a609f546108fc61260a8a600201548561232490919063ffffffff16565b60018b0154610bcf908890612324565b88600101819055505050505050505050565b60006060846001600160a01b031663a9059cbb60e01b858560405160240161265592919061318f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516126de919061315f565b6000604051808303816000865af19150503d806000811461271b576040519150601f19603f3d011682016040523d82523d6000602084013e612720565b606091505b509150915081801561274a57508051158061274a57508080602001905181019061274a9190612e53565b610cc45760405162461bcd60e51b815260040161045a9061330b565b60008282018381101561235e5760405162461bcd60e51b815260040161045a9061339f565b600061235e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506129b7565b600061235e8284026129e3565b303b1590565b600054610100900460ff16806127f957506127f96127da565b80612807575060005460ff16155b6128235760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff1615801561284e576000805460ff1961ff0019909116610100171660011790555b612856612a34565b61285e612ab5565b8015612870576000805461ff00191690555b50565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f95d89b4100000000000000000000000000000000000000000000000000000000179052905160609160009183916001600160a01b038616916128e8919061315f565b600060405180830381855afa9150503d8060008114612923576040519150601f19603f3d011682016040523d82523d6000602084013e612928565b606091505b50915091508161296d576040518060400160405280600381526020017f3f3f3f0000000000000000000000000000000000000000000000000000000000815250612976565b61297681612ba7565b925050505b919050565b600081836129a15760405162461bcd60e51b815260040161045a919061323e565b5060008385816129ad57fe5b0495945050505050565b600081848411156129db5760405162461bcd60e51b815260040161045a919061323e565b505050900390565b60006003821115612a26575080600160028204015b81811015612a2057809150600281828581612a0f57fe5b040181612a1857fe5b0490506129f8565b5061297b565b811561297b57506001919050565b600054610100900460ff1680612a4d5750612a4d6127da565b80612a5b575060005460ff16155b612a775760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff1615801561285e576000805460ff1961ff0019909116610100171660011790558015612870576000805461ff001916905550565b600054610100900460ff1680612ace5750612ace6127da565b80612adc575060005460ff16155b612af85760405162461bcd60e51b815260040161045a906133d6565b600054610100900460ff16158015612b23576000805460ff1961ff0019909116610100171660011790555b6000612b2d6121dc565b603380547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3508015612870576000805461ff001916905550565b60606040825110612bcd5781806020019051810190612bc69190612edb565b905061297b565b815160201415612d355760005b60208160ff16108015612c215750828160ff1681518110612bf757fe5b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612c2e57600101612bda565b60608160ff1667ffffffffffffffff81118015612c4a57600080fd5b506040519080825280601f01601f191660200182016040528015612c75576020820181803683370190505b509050600091505b60208260ff16108015612cc45750838260ff1681518110612c9a57fe5b01602001517fff000000000000000000000000000000000000000000000000000000000000001615155b15612d2c57838260ff1681518110612cd857fe5b602001015160f81c60f81b818360ff1681518110612cf257fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600190910190612c7d565b915061297b9050565b5060408051808201909152600381527f3f3f3f0000000000000000000000000000000000000000000000000000000000602082015261297b565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915290565b60405180606001604052806000815260200160008152602001600081525090565b803563ffffffff8116811461236157600080fd5b80356bffffffffffffffffffffffff8116811461236157600080fd5b600060208284031215612e1d578081fd5b813561235e8161380e565b60008060408385031215612e3a578081fd5b8235612e458161380e565b946020939093013593505050565b600060208284031215612e64578081fd5b815161235e81613823565b600060208284031215612e80578081fd5b815161235e8161380e565b60008060008060808587031215612ea0578182fd5b8435612eab8161380e565b93506020850135612ebb8161380e565b92506040850135612ecb8161380e565b9396929550929360600135925050565b600060208284031215612eec578081fd5b815167ffffffffffffffff80821115612f03578283fd5b818401915084601f830112612f16578283fd5b815181811115612f24578384fd5b612f5560207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016137bb565b9150808252856020828501011115612f6b578384fd5b612f7c8160208401602086016137e2565b50949350505050565b600060808284031215612f96578081fd5b612fa060806137bb565b8251612fab8161380e565b808252506020830151602082015260408301516040820152606083015160608201528091505092915050565b600060208284031215612fe8578081fd5b5035919050565b600060208284031215613000578081fd5b5051919050565b60008060408385031215613019578182fd5b82359150602083013561302b8161380e565b809150509250929050565b60008060408385031215613048578182fd5b50508035926020909101359150565b600080600080600060a0868803121561306e578081fd5b8535945061307f8760208801612df0565b935061308e8760408801612ddc565b9250606086013561309e8161380e565b915060808601356130ae81613823565b809150509295509295909350565b600080600080608085870312156130d1578182fd5b6130db8686612df0565b93506130ea8660208701612ddc565b925060408501356130fa8161380e565b9150606085013561310a8161380e565b939692955090935050565b6000815180845261312d8160208601602086016137e2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082516131718184602087016137e2565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03998a1681526bffffffffffffffffffffffff9890981660208901526040880196909652606087019490945267ffffffffffffffff92909216608086015290941660a084015263ffffffff90931660c083015260e08201929092526101008101919091526101200190565b60006020825261235e6020830184613115565b60208082526022908201527f426f6f737465644e4554544661726d3a207769746864726177206e6f7420676f60408201527f6f64000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526022908201527f426f6f737465644e4554544661726d3a2043616c6c6572206e6f742076654e4560408201527f5454000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601c908201527f426f72696e6745524332303a205472616e73666572206661696c656400000000604082015260600190565b60208082526026908201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160408201527f6464726573730000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201527f647920696e697469616c697a6564000000000000000000000000000000000000606082015260800190565b60208082526021908201527f426f6f737465644e4554544661726d3a204c5020616c7265616479206164646560408201527f6400000000000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252603b908201527f426f6f737465644e4554544661726d3a2076654e45545453686172654270206e60408201527f6565647320746f206265206c6f776572207468616e2031303030300000000000606082015260800190565b6020808252601f908201527f426f6f737465644e4554544661726d3a20546f6f206d616e7920706f6f6c7300604082015260600190565b60208082526035908201527f426f6f737465644e4554544661726d3a20416c7265616479206861732061206260408201527f616c616e6365206f662064756d6d7920746f6b656e0000000000000000000000606082015260800190565b6020808252818101527f426f72696e6745524332303a205472616e7366657246726f6d206661696c6564604082015260600190565b60208082526026908201527f426f6f737465644e4554544661726d3a2042616c616e6365206d75737420657860408201527f6365656420300000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b90815260200190565b60008582526001600160a01b03851660208301526080604083015261370d6080830185613115565b905082606083015295945050505050565b918252602082015260400190565b9283526020830191909152604082015260600190565b67ffffffffffffffff94909416845260208401929092526040830152606082015260800190565b6bffffffffffffffffffffffff92909216825263ffffffff16602082015260400190565b6bffffffffffffffffffffffff93909316835263ffffffff9190911660208301521515604082015260600190565b60405181810167ffffffffffffffff811182821017156137da57600080fd5b604052919050565b60005b838110156137fd5781810151838201526020016137e5565b838111156118a75750506000910152565b6001600160a01b038116811461287057600080fd5b801515811461287057600080fdfea2646970667358221220e18f5c3a4ecbf39c81769fe9ada92baddd9932dffa1e49830f6a6627674394b164736f6c634300060c0033