Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Contract is not verified. However, we found a verified contract with the same bytecode in Blockscout DB 0x79eafcee9e02ca70a9d34cc356e744d3718fda84.
All metadata displayed below is from that contract. In order to verify current contract, click Verify & Publish button
Verify & Publish
All metadata displayed below is from that contract. In order to verify current contract, click Verify & Publish button
- Contract name:
- StakingRewards
- Optimization enabled
- true
- Compiler version
- v0.8.10+commit.fc410830
- Optimization runs
- 1000
- Verified at
- 2021-12-18T05:57:15.702287Z
Contract source code
// File: contracts/interfaces/IElkERC20.sol pragma solidity >=0.5.0; interface IElkERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; } // File: @openzeppelin/contracts@4.3.0/utils/Address.sol pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // File: @openzeppelin/contracts@4.3.0/token/ERC20/IERC20.sol pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File: @openzeppelin/contracts@4.3.0/token/ERC20/utils/SafeERC20.sol pragma solidity ^0.8.0; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } // File: @openzeppelin/contracts@4.3.0/security/ReentrancyGuard.sol pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and 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; } } // File: @openzeppelin/contracts@4.3.0/utils/math/SafeMath.sol pragma solidity ^0.8.0; // CAUTION // This version of SafeMath should only be used with Solidity 0.8 or later, // because it relies on the compiler's built in overflow checks. /** * @dev Wrappers over Solidity's arithmetic operations. * * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler * now has built in overflow checking. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the substraction of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an overflow flag. * * _Available since v3.4._ */ function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. * * _Available since v3.4._ */ function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; } /** * @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 a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { return a * b; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return a / b; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return a % b; } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {trySub}. * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b <= a, errorMessage); return a - b; } } /** * @dev Returns the integer division of two unsigned integers, reverting with custom message on * division by zero. The result is rounded towards zero. * * 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) { unchecked { require(b > 0, errorMessage); return a / b; } } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * reverting with custom message when dividing by zero. * * CAUTION: This function is deprecated because it requires allocating memory for the error * message unnecessarily. For custom revert reasons use {tryMod}. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { unchecked { require(b > 0, errorMessage); return a % b; } } } // File: @openzeppelin/contracts@4.3.0/utils/math/Math.sol pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a / b + (a % b == 0 ? 0 : 1); } } // File: @openzeppelin/contracts@4.3.0/utils/Context.sol pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } // File: @openzeppelin/contracts@4.3.0/security/Pausable.sol pragma solidity ^0.8.0; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File: @openzeppelin/contracts@4.3.0/access/Ownable.sol pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(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"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // File: contracts/StakingRewardsNew.sol pragma solidity ^0.8.0; contract StakingRewards is ReentrancyGuard, Ownable, Pausable { using SafeMath for uint256; using SafeERC20 for IERC20; /* ========== STATE VARIABLES ========== */ IERC20 public rewardsToken; IERC20 public stakingToken; uint256 public periodFinish; uint256 public rewardRate; uint256 public rewardsDuration; uint256 public lastUpdateTime; uint256 public rewardPerTokenStored; mapping(address => uint256) public userRewardPerTokenPaid; mapping(address => uint256) public rewards; IERC20 public boosterToken; uint256 public boosterRewardRate; uint256 public boosterRewardPerTokenStored; mapping(address => uint256) public userBoosterRewardPerTokenPaid; mapping(address => uint256) public boosterRewards; mapping(address => uint256) public coverages; uint256 public totalCoverage; uint256[] public feeSchedule; uint256[] public withdrawalFeesPct; mapping(address => uint256) public lastStakedTime; uint256 public totalFees; uint256 private _totalSupply; mapping(address => uint256) private _balances; /* ========== CONSTRUCTOR ========== */ constructor( address _rewardsToken, address _stakingToken, address _boosterToken, uint256 _rewardsDuration, uint256[] memory _feeSchedule, // assumes a sorted array uint256[] memory _withdrawalFeesPct // aligned to fee schedule, percentage (/1000) ) public { require(_boosterToken != _rewardsToken, "The booster token must be different from the reward token"); require(_boosterToken != _stakingToken, "The booster token must be different from the staking token"); rewardsToken = IERC20(_rewardsToken); stakingToken = IERC20(_stakingToken); boosterToken = IERC20(_boosterToken); rewardsDuration = _rewardsDuration; _setWithdrawalFees(_feeSchedule, _withdrawalFeesPct); _pause(); } /* ========== VIEWS ========== */ function totalSupply() external view returns (uint256) { return _totalSupply; } function balanceOf(address account) external view returns (uint256) { return _balances[account]; } function lastTimeRewardApplicable() public view returns (uint256) { return Math.min(block.timestamp, periodFinish); } function rewardPerToken() public view returns (uint256) { if (_totalSupply == 0) { return rewardPerTokenStored; } return rewardPerTokenStored.add( lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply) ); } function earned(address account) public view returns (uint256) { return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]); } function getRewardForDuration() external view returns (uint256) { return rewardRate.mul(rewardsDuration); } function boosterRewardPerToken() public view returns (uint256) { if (_totalSupply == 0) { return boosterRewardPerTokenStored; } return boosterRewardPerTokenStored.add( lastTimeRewardApplicable().sub(lastUpdateTime).mul(boosterRewardRate).mul(1e18).div(_totalSupply) ); } function boosterEarned(address account) public view returns (uint256) { return _balances[account].mul(boosterRewardPerToken().sub(userBoosterRewardPerTokenPaid[account])).div(1e18).add(boosterRewards[account]); } function getBoosterRewardForDuration() external view returns (uint256) { return boosterRewardRate.mul(rewardsDuration); } function exitFee(address account) public view returns (uint256) { return fee(account, _balances[account]); } function fee(address account, uint256 withdrawalAmount) public view returns (uint256) { for (uint i=0; i < feeSchedule.length; ++i) { if (block.timestamp.sub(lastStakedTime[account]) < feeSchedule[i]) { return withdrawalAmount.mul(withdrawalFeesPct[i]).div(1000); } } return 0; } /* ========== MUTATIVE FUNCTIONS ========== */ function stake(uint256 amount) external nonReentrant whenNotPaused updateReward(msg.sender) { require(amount > 0, "Cannot stake 0"); _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); stakingToken.safeTransferFrom(msg.sender, address(this), amount); lastStakedTime[msg.sender] = block.timestamp; emit Staked(msg.sender, amount); } function stakeWithPermit(uint256 amount, uint deadline, uint8 v, bytes32 r, bytes32 s) external nonReentrant whenNotPaused updateReward(msg.sender) { require(amount > 0, "Cannot stake 0"); _totalSupply = _totalSupply.add(amount); _balances[msg.sender] = _balances[msg.sender].add(amount); // permit IElkERC20(address(stakingToken)).permit(msg.sender, address(this), amount, deadline, v, r, s); stakingToken.safeTransferFrom(msg.sender, address(this), amount); lastStakedTime[msg.sender] = block.timestamp; emit Staked(msg.sender, amount); } function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) { _withdraw(amount); } function emergencyWithdraw(uint256 amount) public nonReentrant { _withdraw(amount); } function _withdraw(uint256 amount) private { require(amount > 0, "Cannot withdraw 0"); _totalSupply = _totalSupply.sub(amount); uint256 collectedFee = fee(msg.sender, amount); _balances[msg.sender] = _balances[msg.sender].sub(amount); uint256 withdrawableBalance = amount.sub(collectedFee); stakingToken.safeTransfer(msg.sender, withdrawableBalance); emit Withdrawn(msg.sender, withdrawableBalance); if (collectedFee > 0) { emit FeesCollected(msg.sender, collectedFee); totalFees = totalFees.add(collectedFee); } } function getReward() public nonReentrant updateReward(msg.sender) { uint256 reward = rewards[msg.sender]; if (reward > 0) { rewards[msg.sender] = 0; rewardsToken.safeTransfer(msg.sender, reward); emit RewardPaid(msg.sender, reward); } } function getBoosterReward() public nonReentrant updateReward(msg.sender) { if (address(boosterToken) != address(0)) { uint256 reward = boosterRewards[msg.sender]; if (reward > 0) { boosterRewards[msg.sender] = 0; boosterToken.safeTransfer(msg.sender, reward); emit BoosterRewardPaid(msg.sender, reward); } } } function getCoverage() public nonReentrant { uint256 coverageAmount = coverages[msg.sender]; if (coverageAmount > 0) { totalCoverage = totalCoverage.sub(coverages[msg.sender]); coverages[msg.sender] = 0; rewardsToken.safeTransfer(msg.sender, coverageAmount); emit CoveragePaid(msg.sender, coverageAmount); } } function exit() external { withdraw(_balances[msg.sender]); getReward(); getBoosterReward(); getCoverage(); } /* ========== RESTRICTED FUNCTIONS ========== */ function sendRewardsAndStartEmission(uint256 reward, uint256 boosterReward, uint256 duration) external onlyOwner /*whenPaused*/ { rewardsToken.safeTransferFrom(owner(), address(this), reward); if (address(boosterToken) != address(0) && boosterReward > 0) { boosterToken.safeTransferFrom(owner(), address(this), boosterReward); } _startEmission(reward, boosterReward, duration); } function startEmission(uint256 reward, uint256 boosterReward, uint256 duration) external onlyOwner /*whenPaused*/ { _startEmission(reward, boosterReward, duration); } function stopEmission() external onlyOwner whenNotPaused { require(block.timestamp < periodFinish, "Cannot stop rewards emissions if not started or already finished"); uint256 tokensToBurn; uint256 boosterTokensToBurn; if (_totalSupply == 0) { tokensToBurn = rewardsToken.balanceOf(address(this)); if (address(boosterToken) != address(0)) { boosterTokensToBurn = boosterToken.balanceOf(address(this)); } else { boosterTokensToBurn = 0; } } else { uint256 remaining = periodFinish.sub(block.timestamp); tokensToBurn = rewardRate.mul(remaining); boosterTokensToBurn = boosterRewardRate.mul(remaining); } periodFinish = block.timestamp; if (tokensToBurn > 0) { rewardsToken.safeTransfer(owner(), tokensToBurn); } if (address(boosterToken) != address(0) && boosterTokensToBurn > 0) { boosterToken.safeTransfer(owner(), boosterTokensToBurn); } _pause(); emit RewardsEmissionEnded(tokensToBurn); } function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner { require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token"); IERC20(tokenAddress).safeTransfer(owner(), tokenAmount); emit Recovered(tokenAddress, tokenAmount); } function recoverLeftoverReward() external onlyOwner { require(_totalSupply == 0 && rewardsToken == stakingToken, "Cannot recover leftover reward if it is not the staking token or there are still staked tokens"); uint256 tokensToBurn = rewardsToken.balanceOf(address(this)); if (tokensToBurn > 0) { rewardsToken.safeTransfer(owner(), tokensToBurn); } emit LeftoverRewardRecovered(tokensToBurn); } function recoverLeftoverBooster() external onlyOwner { require(address(boosterToken) != address(0), "Cannot recover leftover booster if there was no booster token set"); require(_totalSupply == 0, "Cannot recover leftover booster if there are still staked tokens"); uint256 tokensToBurn = boosterToken.balanceOf(address(this)); if (tokensToBurn > 0) { boosterToken.safeTransfer(owner(), tokensToBurn); } emit LeftoverBoosterRecovered(tokensToBurn); } function recoverFees() external onlyOwner { stakingToken.safeTransfer(owner(), totalFees); emit FeesRecovered(totalFees); totalFees = 0; } function setReward(address addr, uint256 amount) public onlyOwner { rewards[addr] = amount; } function setRewards(address[] memory addresses, uint256[] memory amounts) external onlyOwner { require(addresses.length == amounts.length, "The same number of addresses and amounts must be provided"); for (uint i=0; i < addresses.length; ++i) { setReward(addresses[i], amounts[i]); } } function setRewardsDuration(uint256 duration) external onlyOwner { require( block.timestamp > periodFinish, "Previous rewards period must be complete before changing the duration for the new period" ); _setRewardsDuration(duration); } // Booster Rewards function setBoosterToken(address _boosterToken) external onlyOwner { require(_boosterToken != address(rewardsToken), "The booster token must be different from the reward token"); require(_boosterToken != address(stakingToken), "The booster token must be different from the staking token"); boosterToken = IERC20(_boosterToken); emit BoosterRewardSet(_boosterToken); } function setBoosterReward(address addr, uint256 amount) public onlyOwner { boosterRewards[addr] = amount; } function setBoosterRewards(address[] memory addresses, uint256[] memory amounts) external onlyOwner { require(addresses.length == amounts.length, "The same number of addresses and amounts must be provided"); for (uint i=0; i < addresses.length; ++i) { setBoosterReward(addresses[i], amounts[i]); } } // ILP function setCoverageAmount(address addr, uint256 amount) public onlyOwner { totalCoverage = totalCoverage.sub(coverages[addr]); coverages[addr] = amount; totalCoverage = totalCoverage.add(coverages[addr]); } function setCoverageAmounts(address[] memory addresses, uint256[] memory amounts) external onlyOwner { require(addresses.length == amounts.length, "The same number of addresses and amounts must be provided"); for (uint i=0; i < addresses.length; ++i) { setCoverageAmount(addresses[i], amounts[i]); } } function pause() public virtual { _pause(); } function unpause() public virtual { _unpause(); } // Withdrawal Fees function setWithdrawalFees(uint256[] memory _feeSchedule, uint256[] memory _withdrawalFees) external onlyOwner { _setWithdrawalFees(_feeSchedule, _withdrawalFees); } // Private functions function _setRewardsDuration(uint256 duration) private { rewardsDuration = duration; emit RewardsDurationUpdated(rewardsDuration); } function _setWithdrawalFees(uint256[] memory _feeSchedule, uint256[] memory _withdrawalFeesPct) private { require(_feeSchedule.length == _withdrawalFeesPct.length, "Fee schedule and withdrawal fees arrays must be the same length!"); feeSchedule = _feeSchedule; withdrawalFeesPct = _withdrawalFeesPct; emit WithdrawalFeesSet(_feeSchedule, _withdrawalFeesPct); } // Must send reward before calling this! function _startEmission(uint256 reward, uint256 boosterReward, uint256 duration) private updateReward(address(0)) { if (duration > 0) { _setRewardsDuration(duration); } if (block.timestamp >= periodFinish) { rewardRate = reward.div(rewardsDuration); boosterRewardRate = boosterReward.div(rewardsDuration); } else { uint256 remaining = periodFinish.sub(block.timestamp); uint256 leftover = remaining.mul(rewardRate); rewardRate = reward.add(leftover).div(rewardsDuration); uint256 boosterLeftover = remaining.mul(boosterRewardRate); boosterRewardRate = boosterReward.add(boosterLeftover).div(rewardsDuration); } // Ensure the provided reward amount is not more than the balance in the contract. // This keeps the reward rate in the right range, preventing overflows due to // very high values of rewardRate in the earned and rewardsPerToken functions; // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow. uint balance = rewardsToken.balanceOf(address(this)); require(rewardRate <= balance.div(rewardsDuration) || (rewardsToken == stakingToken && rewardRate <= balance.div(rewardsDuration).sub(_totalSupply)), "Provided reward too high"); if (address(boosterToken) != address(0)) { uint boosterBalance = boosterToken.balanceOf(address(this)); require(boosterRewardRate <= boosterBalance.div(rewardsDuration), "Provided booster reward too high"); } lastUpdateTime = block.timestamp; periodFinish = block.timestamp.add(rewardsDuration); _unpause(); emit RewardsEmissionStarted(reward, boosterReward, duration); } /* ========== DEPRECATED ========== */ function coverageOf(address account) external view returns (uint256) { return coverages[account]; } function updateLastTime(uint timestamp) external onlyOwner { lastUpdateTime = timestamp; } /* ========== MODIFIERS ========== */ modifier updateReward(address account) { rewardPerTokenStored = rewardPerToken(); boosterRewardPerTokenStored = boosterRewardPerToken(); lastUpdateTime = lastTimeRewardApplicable(); if (account != address(0)) { rewards[account] = earned(account); userRewardPerTokenPaid[account] = rewardPerTokenStored; boosterRewards[account] = boosterEarned(account); userBoosterRewardPerTokenPaid[account] = boosterRewardPerTokenStored; } _; } /* ========== EVENTS ========== */ event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event CoveragePaid(address indexed user, uint256 amount); event RewardPaid(address indexed user, uint256 reward); event BoosterRewardPaid(address indexed user, uint256 reward); event RewardsDurationUpdated(uint256 newDuration); event Recovered(address token, uint256 amount); event LeftoverRewardRecovered(uint256 amount); event LeftoverBoosterRecovered(uint256 amount); event RewardsEmissionStarted(uint256 reward, uint256 boosterReward, uint256 duration); event RewardsEmissionEnded(uint256 amount); event BoosterRewardSet(address token); event WithdrawalFeesSet(uint256[] _feeSchedule, uint256[] _withdrawalFees); event FeesCollected(address indexed user, uint256 amount); event FeesRecovered(uint256 amount); }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_rewardsToken","internalType":"address"},{"type":"address","name":"_stakingToken","internalType":"address"},{"type":"address","name":"_boosterToken","internalType":"address"},{"type":"uint256","name":"_rewardsDuration","internalType":"uint256"},{"type":"uint256[]","name":"_feeSchedule","internalType":"uint256[]"},{"type":"uint256[]","name":"_withdrawalFeesPct","internalType":"uint256[]"}]},{"type":"event","name":"BoosterRewardPaid","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"BoosterRewardSet","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"CoveragePaid","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FeesCollected","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"FeesRecovered","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LeftoverBoosterRecovered","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"LeftoverRewardRecovered","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":"Paused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Recovered","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardPaid","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsDurationUpdated","inputs":[{"type":"uint256","name":"newDuration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsEmissionEnded","inputs":[{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardsEmissionStarted","inputs":[{"type":"uint256","name":"reward","internalType":"uint256","indexed":false},{"type":"uint256","name":"boosterReward","internalType":"uint256","indexed":false},{"type":"uint256","name":"duration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Staked","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Unpaused","inputs":[{"type":"address","name":"account","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrawalFeesSet","inputs":[{"type":"uint256[]","name":"_feeSchedule","internalType":"uint256[]","indexed":false},{"type":"uint256[]","name":"_withdrawalFees","internalType":"uint256[]","indexed":false}],"anonymous":false},{"type":"event","name":"Withdrawn","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"boosterEarned","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"boosterRewardPerToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"boosterRewardPerTokenStored","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"boosterRewardRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"boosterRewards","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"boosterToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"coverageOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"coverages","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"earned","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyWithdraw","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"exit","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"exitFee","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"fee","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"uint256","name":"withdrawalAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"feeSchedule","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getBoosterReward","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBoosterRewardForDuration","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getCoverage","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getReward","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardForDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastStakedTime","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastTimeRewardApplicable","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastUpdateTime","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"pause","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"paused","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"periodFinish","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverERC20","inputs":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverFees","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverLeftoverBooster","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverLeftoverReward","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerTokenStored","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewards","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardsDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"rewardsToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"sendRewardsAndStartEmission","inputs":[{"type":"uint256","name":"reward","internalType":"uint256"},{"type":"uint256","name":"boosterReward","internalType":"uint256"},{"type":"uint256","name":"duration","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBoosterReward","inputs":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBoosterRewards","inputs":[{"type":"address[]","name":"addresses","internalType":"address[]"},{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBoosterToken","inputs":[{"type":"address","name":"_boosterToken","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCoverageAmount","inputs":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCoverageAmounts","inputs":[{"type":"address[]","name":"addresses","internalType":"address[]"},{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setReward","inputs":[{"type":"address","name":"addr","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewards","inputs":[{"type":"address[]","name":"addresses","internalType":"address[]"},{"type":"uint256[]","name":"amounts","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardsDuration","inputs":[{"type":"uint256","name":"duration","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setWithdrawalFees","inputs":[{"type":"uint256[]","name":"_feeSchedule","internalType":"uint256[]"},{"type":"uint256[]","name":"_withdrawalFees","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stake","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stakeWithPermit","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"stakingToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"startEmission","inputs":[{"type":"uint256","name":"reward","internalType":"uint256"},{"type":"uint256","name":"boosterReward","internalType":"uint256"},{"type":"uint256","name":"duration","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stopEmission","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalCoverage","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalFees","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"unpause","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateLastTime","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"userBoosterRewardPerTokenPaid","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"userRewardPerTokenPaid","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"withdrawalFeesPct","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]}]
Contract Creation Code
0x60806040523480156200001157600080fd5b5060405162003ef038038062003ef08339810160408190526200003491620004ca565b60016000556200004433620001a5565b6001805460ff60a01b191690556001600160a01b038481169087161415620000c85760405162461bcd60e51b8152602060048201526039602482015260008051602062003ed083398151915260448201527f656e742066726f6d207468652072657761726420746f6b656e0000000000000060648201526084015b60405180910390fd5b846001600160a01b0316846001600160a01b03161415620001415760405162461bcd60e51b815260206004820152603a602482015260008051602062003ed083398151915260448201527f656e742066726f6d20746865207374616b696e6720746f6b656e0000000000006064820152608401620000bf565b600280546001600160a01b038089166001600160a01b03199283161790925560038054888416908316179055600b80549287169290911691909117905560068390556200018f8282620001f7565b62000199620002dd565b505050505050620005e4565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b805182511462000272576040805162461bcd60e51b81526020600482015260248101919091527f466565207363686564756c6520616e64207769746864726177616c206665657360448201527f20617272617973206d757374206265207468652073616d65206c656e677468216064820152608401620000bf565b8151620002879060129060208501906200038c565b5080516200029d9060139060208401906200038c565b507fe5a2c1e4acf2a2da539a1183c56fbbcec4b66dbc828b76f1c1bf365f1887886b8282604051620002d1929190620005b2565b60405180910390a15050565b620002f1600154600160a01b900460ff1690565b15620003335760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401620000bf565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586200036f3390565b6040516001600160a01b03909116815260200160405180910390a1565b828054828255906000526020600020908101928215620003ca579160200282015b82811115620003ca578251825591602001919060010190620003ad565b50620003d8929150620003dc565b5090565b5b80821115620003d85760008155600101620003dd565b80516001600160a01b03811681146200040b57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200043857600080fd5b815160206001600160401b038083111562000457576200045762000410565b8260051b604051601f19603f830116810181811084821117156200047f576200047f62000410565b6040529384528581018301938381019250878511156200049e57600080fd5b83870191505b84821015620004bf57815183529183019190830190620004a4565b979650505050505050565b60008060008060008060c08789031215620004e457600080fd5b620004ef87620003f3565b9550620004ff60208801620003f3565b94506200050f60408801620003f3565b6060880151608089015191955093506001600160401b03808211156200053457600080fd5b620005428a838b0162000426565b935060a08901519150808211156200055957600080fd5b506200056889828a0162000426565b9150509295509295509295565b600081518084526020808501945080840160005b83811015620005a75781518752958201959082019060010162000589565b509495945050505050565b604081526000620005c7604083018562000575565b8281036020840152620005db818562000575565b95945050505050565b6138dc80620005f46000396000f3fe608060405234801561001057600080fd5b50600436106103c45760003560e01c806380faa57d116101ff578063cd3daf9d1161011a578063ebe2b12b116100ad578063f3f0ffda1161007c578063f3f0ffda146107cd578063f86e55ca146107d5578063faef375e146107e8578063ffb13208146107f057600080fd5b8063ebe2b12b1461077e578063ecd9ba8214610787578063f22797d81461079a578063f2fde38b146107ba57600080fd5b8063d9142bbe116100e9578063d9142bbe14610747578063df136d651461075a578063e9fad8ee14610763578063eacccaf01461076b57600080fd5b8063cd3daf9d1461071b578063cdeae37114610723578063d1af0c7d1461072b578063d51942e21461073e57600080fd5b80639292052211610192578063be0bf75111610161578063be0bf751146106d6578063c57a202c146106df578063c8f33c91146106ff578063cc1a378f1461070857600080fd5b8063929205221461068a5780639465d4a11461069d5780639e6eda18146106b0578063a694fc3a146106c357600080fd5b80638bb95b45116101ce5780638bb95b45146106405780638da5cb5b146106535780638f0bb79c14610664578063905b7d3c1461067757600080fd5b806380faa57d146105fd5780638456cb59146106055780638980f11f1461060d5780638b8763471461062057600080fd5b80633f4ba83a116102ef57806366a03c7f1161028257806372f702f31161025157806372f702f3146105bb57806377075130146105ce57806377191605146105e15780637b0a47ee146105f457600080fd5b806366a03c7f146105795780636de4ab871461058257806370a082311461058a578063715018a6146105b357600080fd5b8063576c23ab116102be578063576c23ab146105095780635c975abb146105345780635d129544146105515780636439ea4c1461057157600080fd5b80633f4ba83a146104c857806343d45c17146104d05780634b03f2e9146104e35780635312ea8e146104f657600080fd5b80631c1f78eb1161036757806335ceec0f1161033657806335ceec0f14610491578063386a9525146104a45780633b8e4f7e146104ad5780633d18b912146104c057600080fd5b80631c1f78eb146104665780632459a6991461046e5780632cbe61d3146104765780632e1a7d4d1461047e57600080fd5b806310cbbe38116103a357806310cbbe3814610419578063120459871461042c57806313114a9d1461045557806318160ddd1461045e57600080fd5b80628cc262146103c95780630700037d146103ef5780630e9bb0a31461040f575b600080fd5b6103dc6103d73660046133f4565b610810565b6040519081526020015b60405180910390f35b6103dc6103fd3660046133f4565b600a6020526000908152604090205481565b61041761088e565b005b6103dc6104273660046133f4565b610b97565b6103dc61043a3660046133f4565b6001600160a01b031660009081526010602052604090205490565b6103dc60155481565b6016546103dc565b6103dc610bbb565b610417610bd9565b610417610d5c565b61041761048c36600461340f565b610f30565b6103dc61049f36600461340f565b61102b565b6103dc60065481565b6103dc6104bb3660046133f4565b61104c565b610417611093565b6104176111f6565b6104176104de366004613428565b611200565b6104176104f1366004613428565b61129f565b61041761050436600461340f565b611303565b600b5461051c906001600160a01b031681565b6040516001600160a01b0390911681526020016103e6565b600154600160a01b900460ff1660405190151581526020016103e6565b6103dc61055f3660046133f4565b600e6020526000908152604090205481565b6103dc611364565b6103dc600d5481565b6104176113b0565b6103dc6105983660046133f4565b6001600160a01b031660009081526017602052604090205490565b6104176114a2565b60035461051c906001600160a01b031681565b6104176105dc366004613528565b6114f4565b6104176105ef36600461358c565b61154a565b6103dc60055481565b6103dc611613565b610417611621565b61041761061b366004613428565b611629565b6103dc61062e3660046133f4565b60096020526000908152604090205481565b61041761064e36600461358c565b61175a565b6001546001600160a01b031661051c565b6103dc61067236600461340f565b6117a2565b6104176106853660046135b8565b6117b2565b6104176106983660046135b8565b6118c9565b6104176106ab3660046133f4565b6119e0565b6103dc6106be366004613428565b611b8b565b6104176106d136600461340f565b611c3a565b6103dc600c5481565b6103dc6106ed3660046133f4565b60146020526000908152604090205481565b6103dc60075481565b61041761071636600461340f565b611e64565b6103dc611f55565b610417611f9b565b60025461051c906001600160a01b031681565b6103dc60115481565b61041761075536600461340f565b612050565b6103dc60085481565b61041761209d565b610417610779366004613428565b6120ce565b6103dc60045481565b610417610795366004613661565b612132565b6103dc6107a83660046133f4565b600f6020526000908152604090205481565b6104176107c83660046133f4565b612414565b6103dc6124e1565b6104176107e33660046135b8565b6124fa565b610417612611565b6103dc6107fe3660046133f4565b60106020526000908152604090205481565b6001600160a01b0381166000908152600a60209081526040808320546009909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611f55565b9061282f565b6001600160a01b03881660009081526017602052604090205490612842565b9061284e565b9061285a565b92915050565b6001546001600160a01b031633146108db5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064015b60405180910390fd5b600154600160a01b900460ff16156109285760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b60045442106109a1576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f742073746f70207265776172647320656d697373696f6e7320696660448201527f206e6f742073746172746564206f7220616c72656164792066696e697368656460648201526084016108d2565b60008060165460001415610aaa576002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156109f7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1b91906136b0565b600b549092506001600160a01b031615610aa257600b546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9b91906136b0565b9050610ade565b506000610ade565b600454600090610aba904261282f565b600554909150610aca9082612842565b600c54909350610ada9082612842565b9150505b426004558115610b1057610b10610afd6001546001600160a01b031690565b6002546001600160a01b03169084612866565b600b546001600160a01b031615801590610b2a5750600081115b15610b5757610b57610b446001546001600160a01b031690565b600b546001600160a01b03169083612866565b610b5f61290f565b6040518281527f6d815f6a8a51efb6f4140923189859b9e9caaa228c9334179e8eb7edefc6838e906020015b60405180910390a15050565b6001600160a01b038116600090815260176020526040812054610888908390611b8b565b6000610bd460065460055461284290919063ffffffff16565b905090565b60026000541415610c2c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610c3a611f55565b600855610c45611364565b600d55610c50611613565b6007556001600160a01b03811615610ccb57610c6b81610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610c9f8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600b546001600160a01b031615610d5457336000908152600f60205260409020548015610d5257336000818152600f6020526040812055600b54610d1b916001600160a01b039091169083612866565b60405181815233907fd1e5531ac01ffc9c7971b52c82806a6e5ae8907ddedd2e3153afaafcfdf175d6906020015b60405180910390a25b505b506001600055565b6001546001600160a01b03163314610da45760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b601654158015610dc457506003546002546001600160a01b039081169116145b610e5c5760405162461bcd60e51b815260206004820152605e60248201527f43616e6e6f74207265636f766572206c6566746f76657220726577617264206960448201527f66206974206973206e6f7420746865207374616b696e6720746f6b656e206f7260648201527f20746865726520617265207374696c6c207374616b656420746f6b656e730000608482015260a4016108d2565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec991906136b0565b90508015610ef957610ef9610ee66001546001600160a01b031690565b6002546001600160a01b03169083612866565b6040518181527ff6d91c6a1bf05d7c0f2c157905a97d3bc2f860a1402d71dd52a27fabb5bcaf8d906020015b60405180910390a150565b60026000541415610f835760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610f91611f55565b600855610f9c611364565b600d55610fa7611613565b6007556001600160a01b0381161561102257610fc281610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610ff68161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b610d52826129b4565b6012818154811061103b57600080fd5b600091825260209091200154905081565b6001600160a01b0381166000908152600f6020908152604080832054600e909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611364565b600260005414156110e65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055336110f4611f55565b6008556110ff611364565b600d5561110a611613565b6007556001600160a01b038116156111855761112581610810565b6001600160a01b0382166000908152600a60209081526040808320939093556008546009909152919020556111598161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b336000908152600a60205260409020548015610d5257336000818152600a60205260408120556002546111c4916001600160a01b039091169083612866565b60405181815233907fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048690602001610d49565b6111fe612af9565b565b6001546001600160a01b031633146112485760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b03821660009081526010602052604090205460115461126d9161282f565b60119081556001600160a01b038316600090815260106020526040902082905554611298908261285a565b6011555050565b6001546001600160a01b031633146112e75760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b039091166000908152600f6020526040902055565b600260005414156113565760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055610d54816129b4565b6000601654600014156113785750600d5490565b610bd46113a760165461087c670de0b6b3a76400006113a1600c546113a1600754610857611613565b90612842565b600d549061285a565b600260005414156114035760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b60026000908155338152601060205260409020548015610d5457336000908152601060205260409020546011546114399161282f565b60115533600081815260106020526040812055600254611465916001600160a01b039091169083612866565b60405181815233907fef4696bdcf47e292773442e4169d670e1b2d0d3f5ceff2a5c1e236c10109ee809060200160405180910390a2506001600055565b6001546001600160a01b031633146114ea5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6111fe6000612b86565b6001546001600160a01b0316331461153c5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6115468282612be5565b5050565b6001546001600160a01b031633146115925760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6115bb6115a76001546001600160a01b031690565b6002546001600160a01b0316903086612cb7565b600b546001600160a01b0316158015906115d55750600082115b15611603576116036115ef6001546001600160a01b031690565b600b546001600160a01b0316903085612cb7565b61160e838383612d0e565b505050565b6000610bd4426004546130b9565b6111fe61290f565b6001546001600160a01b031633146116715760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6003546001600160a01b03838116911614156116f55760405162461bcd60e51b815260206004820152602160248201527f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560448201527f6e0000000000000000000000000000000000000000000000000000000000000060648201526084016108d2565b61171b61170a6001546001600160a01b031690565b6001600160a01b0384169083612866565b604080516001600160a01b0384168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa289101610b8b565b6001546001600160a01b031633146116035760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6013818154811061103b57600080fd5b6001546001600160a01b031633146117fa5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146118715760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576118b9838281518110611892576118926136c9565b60200260200101518383815181106118ac576118ac6136c9565b6020026020010151611200565b6118c2816136f5565b9050611874565b6001546001600160a01b031633146119115760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146119885760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576119d08382815181106119a9576119a96136c9565b60200260200101518383815181106119c3576119c36136c9565b60200260200101516120ce565b6119d9816136f5565b905061198b565b6001546001600160a01b03163314611a285760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6002546001600160a01b0382811691161415611aac5760405162461bcd60e51b815260206004820152603960248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d207468652072657761726420746f6b656e0000000000000060648201526084016108d2565b6003546001600160a01b0382811691161415611b305760405162461bcd60e51b815260206004820152603a60248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d20746865207374616b696e6720746f6b656e00000000000060648201526084016108d2565b600b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f0c6fec5b80219c372da56cb4d1ef3e172069953fa5c72ececf0d0dfe1109260b90602001610f25565b6000805b601254811015611c305760128181548110611bac57611bac6136c9565b60009182526020808320909101546001600160a01b03871683526014909152604090912054611bdc90429061282f565b1015611c2057611c186103e861087c60138481548110611bfe57611bfe6136c9565b90600052602060002001548661284290919063ffffffff16565b915050610888565b611c29816136f5565b9050611b8f565b5060009392505050565b60026000541415611c8d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff1615611cdf5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b33611ce8611f55565b600855611cf3611364565b600d55611cfe611613565b6007556001600160a01b03811615611d7957611d1981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055611d4d8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b60008211611dc95760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b601654611dd6908361285a565b60165533600090815260176020526040902054611df3908361285a565b33600081815260176020526040902091909155600354611e20916001600160a01b03909116903085612cb7565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d90610d499085815260200190565b6001546001600160a01b03163314611eac5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6004544211611f495760405162461bcd60e51b815260206004820152605860248201527f50726576696f7573207265776172647320706572696f64206d7573742062652060448201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260648201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000608482015260a4016108d2565b611f52816130cf565b50565b600060165460001415611f69575060085490565b610bd4611f9260165461087c670de0b6b3a76400006113a16005546113a1600754610857611613565b6008549061285a565b6001546001600160a01b03163314611fe35760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b61200e611ff86001546001600160a01b031690565b6015546003546001600160a01b03169190612866565b7f6857c770f3cb43e9c19050a37dd914ec876241c1f4b487d26a1d4f5d3054f49b60155460405161204191815260200190565b60405180910390a16000601555565b6001546001600160a01b031633146120985760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b600755565b336000908152601760205260409020546120b690610f30565b6120be611093565b6120c6610bd9565b6111fe6113b0565b6001546001600160a01b031633146121165760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b039091166000908152600a6020526040902055565b600260005414156121855760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff16156121d75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b336121e0611f55565b6008556121eb611364565b600d556121f6611613565b6007556001600160a01b038116156122715761221181610810565b6001600160a01b0382166000908152600a60209081526040808320939093556008546009909152919020556122458161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600086116122c15760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b6016546122ce908761285a565b601655336000908152601760205260409020546122eb908761285a565b33600081815260176020526040908190209290925560035491517fd505accf0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c481018490526001600160a01b039091169063d505accf9060e401600060405180830381600087803b15801561238a57600080fd5b505af115801561239e573d6000803e3d6000fd5b50506003546123bb92506001600160a01b03169050333089612cb7565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906123ff9089815260200190565b60405180910390a25050600160005550505050565b6001546001600160a01b0316331461245c5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b0381166124d85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016108d2565b611f5281612b86565b6000610bd4600654600c5461284290919063ffffffff16565b6001546001600160a01b031633146125425760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146125b95760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576126018382815181106125da576125da6136c9565b60200260200101518383815181106125f4576125f46136c9565b602002602001015161129f565b61260a816136f5565b90506125bc565b6001546001600160a01b031633146126595760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b600b546001600160a01b03166126fd5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520776173206e6f20626f6f7374657220746f6b656e20736560648201527f7400000000000000000000000000000000000000000000000000000000000000608482015260a4016108d2565b60165415612775576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520617265207374696c6c207374616b656420746f6b656e7360648201526084016108d2565b600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e291906136b0565b905080156127ff576127ff610b446001546001600160a01b031690565b6040518181527fa075ee3dcd38efb87f0f97160a935b6a43768378263338beea06b9681f66151d90602001610f25565b600061283b8284613710565b9392505050565b600061283b8284613727565b600061283b8284613746565b600061283b8284613768565b6040516001600160a01b03831660248201526044810182905261160e9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613104565b600154600160a01b900460ff161561295c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129973390565b6040516001600160a01b03909116815260200160405180910390a1565b60008111612a045760405162461bcd60e51b815260206004820152601160248201527f43616e6e6f74207769746864726177203000000000000000000000000000000060448201526064016108d2565b601654612a11908261282f565b6016556000612a203383611b8b565b33600090815260176020526040902054909150612a3d908361282f565b33600090815260176020526040812091909155612a5a838361282f565b600354909150612a74906001600160a01b03163383612866565b60405181815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d59060200160405180910390a2811561160e5760405182815233907f9dc46f23cfb5ddcad0ae7ea2be38d47fec07bb9382ec7e564efc69e036dd66ce9060200160405180910390a2601554612af1908361285a565b601555505050565b600154600160a01b900460ff16612b525760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016108d2565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612997565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8051825114612c5e576040805162461bcd60e51b81526020600482015260248101919091527f466565207363686564756c6520616e64207769746864726177616c206665657360448201527f20617272617973206d757374206265207468652073616d65206c656e6774682160648201526084016108d2565b8151612c71906012906020850190613378565b508051612c85906013906020840190613378565b507fe5a2c1e4acf2a2da539a1183c56fbbcec4b66dbc828b76f1c1bf365f1887886b8282604051610b8b9291906137bb565b6040516001600160a01b0380851660248301528316604482015260648101829052612d089085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016128ab565b50505050565b6000612d18611f55565b600855612d23611364565b600d55612d2e611613565b6007556001600160a01b03811615612da957612d4981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055612d7d8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b8115612db857612db8826130cf565b6004544210612de857600654612dcf90859061284e565b600555600654612de090849061284e565b600c55612e54565b600454600090612df8904261282f565b90506000612e116005548361284290919063ffffffff16565b600654909150612e259061087c888461285a565b600555600c54600090612e39908490612842565b600654909150612e4d9061087c888461285a565b600c555050505b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec191906136b0565b9050612ed86006548261284e90919063ffffffff16565b600554111580612f1f57506003546002546001600160a01b039081169116148015612f1f5750612f196016546108576006548461284e90919063ffffffff16565b60055411155b612f6b5760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f2068696768000000000000000060448201526064016108d2565b600b546001600160a01b03161561305357600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612fc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe991906136b0565b90506130006006548261284e90919063ffffffff16565b600c5411156130515760405162461bcd60e51b815260206004820181905260248201527f50726f766964656420626f6f737465722072657761726420746f6f206869676860448201526064016108d2565b505b426007819055600654613066919061285a565b600455613071612af9565b60408051868152602081018690529081018490527f748824204e79acdab8f1a9977cbc584250e206ad90d05ef198799f9d6ee93a7d9060600160405180910390a15050505050565b60008183106130c8578161283b565b5090919050565b60068190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610f25565b6000613159826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131e99092919063ffffffff16565b80519091501561160e578080602001905181019061317791906137e9565b61160e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108d2565b60606131f88484600085613200565b949350505050565b6060824710156132785760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016108d2565b843b6132c65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d2565b600080866001600160a01b031685876040516132e29190613837565b60006040518083038185875af1925050503d806000811461331f576040519150601f19603f3d011682016040523d82523d6000602084013e613324565b606091505b509150915061333482828661333f565b979650505050505050565b6060831561334e57508161283b565b82511561335e5782518084602001fd5b8160405162461bcd60e51b81526004016108d29190613853565b8280548282559060005260206000209081019282156133b3579160200282015b828111156133b3578251825591602001919060010190613398565b506133bf9291506133c3565b5090565b5b808211156133bf57600081556001016133c4565b80356001600160a01b03811681146133ef57600080fd5b919050565b60006020828403121561340657600080fd5b61283b826133d8565b60006020828403121561342157600080fd5b5035919050565b6000806040838503121561343b57600080fd5b613444836133d8565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561349157613491613452565b604052919050565b600067ffffffffffffffff8211156134b3576134b3613452565b5060051b60200190565b600082601f8301126134ce57600080fd5b813560206134e36134de83613499565b613468565b82815260059290921b8401810191818101908684111561350257600080fd5b8286015b8481101561351d5780358352918301918301613506565b509695505050505050565b6000806040838503121561353b57600080fd5b823567ffffffffffffffff8082111561355357600080fd5b61355f868387016134bd565b9350602085013591508082111561357557600080fd5b50613582858286016134bd565b9150509250929050565b6000806000606084860312156135a157600080fd5b505081359360208301359350604090920135919050565b600080604083850312156135cb57600080fd5b823567ffffffffffffffff808211156135e357600080fd5b818501915085601f8301126135f757600080fd5b813560206136076134de83613499565b82815260059290921b8401810191818101908984111561362657600080fd5b948201945b8386101561364b5761363c866133d8565b8252948201949082019061362b565b9650508601359250508082111561357557600080fd5b600080600080600060a0868803121561367957600080fd5b8535945060208601359350604086013560ff8116811461369857600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156136c257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613709576137096136df565b5060010190565b600082821015613722576137226136df565b500390565b6000816000190483118215151615613741576137416136df565b500290565b60008261376357634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561377b5761377b6136df565b500190565b600081518084526020808501945080840160005b838110156137b057815187529582019590820190600101613794565b509495945050505050565b6040815260006137ce6040830185613780565b82810360208401526137e08185613780565b95945050505050565b6000602082840312156137fb57600080fd5b8151801515811461283b57600080fd5b60005b8381101561382657818101518382015260200161380e565b83811115612d085750506000910152565b6000825161384981846020870161380b565b9190910192915050565b602081526000825180602084015261387281604085016020870161380b565b601f01601f1916919091016040019291505056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220362c2bfa3419b92432acb1e48c03aab4e6617c26e4c399ff72ecafc77942c73364736f6c634300080a003354686520626f6f7374657220746f6b656e206d75737420626520646966666572000000000000000000000000e1c110e1b1b4a1ded0caf3e42bfbdbb7b5d7ce1c0000000000000000000000001cf3ca3c3d185e75390feb7b1606be20a1cae0c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e248000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106103c45760003560e01c806380faa57d116101ff578063cd3daf9d1161011a578063ebe2b12b116100ad578063f3f0ffda1161007c578063f3f0ffda146107cd578063f86e55ca146107d5578063faef375e146107e8578063ffb13208146107f057600080fd5b8063ebe2b12b1461077e578063ecd9ba8214610787578063f22797d81461079a578063f2fde38b146107ba57600080fd5b8063d9142bbe116100e9578063d9142bbe14610747578063df136d651461075a578063e9fad8ee14610763578063eacccaf01461076b57600080fd5b8063cd3daf9d1461071b578063cdeae37114610723578063d1af0c7d1461072b578063d51942e21461073e57600080fd5b80639292052211610192578063be0bf75111610161578063be0bf751146106d6578063c57a202c146106df578063c8f33c91146106ff578063cc1a378f1461070857600080fd5b8063929205221461068a5780639465d4a11461069d5780639e6eda18146106b0578063a694fc3a146106c357600080fd5b80638bb95b45116101ce5780638bb95b45146106405780638da5cb5b146106535780638f0bb79c14610664578063905b7d3c1461067757600080fd5b806380faa57d146105fd5780638456cb59146106055780638980f11f1461060d5780638b8763471461062057600080fd5b80633f4ba83a116102ef57806366a03c7f1161028257806372f702f31161025157806372f702f3146105bb57806377075130146105ce57806377191605146105e15780637b0a47ee146105f457600080fd5b806366a03c7f146105795780636de4ab871461058257806370a082311461058a578063715018a6146105b357600080fd5b8063576c23ab116102be578063576c23ab146105095780635c975abb146105345780635d129544146105515780636439ea4c1461057157600080fd5b80633f4ba83a146104c857806343d45c17146104d05780634b03f2e9146104e35780635312ea8e146104f657600080fd5b80631c1f78eb1161036757806335ceec0f1161033657806335ceec0f14610491578063386a9525146104a45780633b8e4f7e146104ad5780633d18b912146104c057600080fd5b80631c1f78eb146104665780632459a6991461046e5780632cbe61d3146104765780632e1a7d4d1461047e57600080fd5b806310cbbe38116103a357806310cbbe3814610419578063120459871461042c57806313114a9d1461045557806318160ddd1461045e57600080fd5b80628cc262146103c95780630700037d146103ef5780630e9bb0a31461040f575b600080fd5b6103dc6103d73660046133f4565b610810565b6040519081526020015b60405180910390f35b6103dc6103fd3660046133f4565b600a6020526000908152604090205481565b61041761088e565b005b6103dc6104273660046133f4565b610b97565b6103dc61043a3660046133f4565b6001600160a01b031660009081526010602052604090205490565b6103dc60155481565b6016546103dc565b6103dc610bbb565b610417610bd9565b610417610d5c565b61041761048c36600461340f565b610f30565b6103dc61049f36600461340f565b61102b565b6103dc60065481565b6103dc6104bb3660046133f4565b61104c565b610417611093565b6104176111f6565b6104176104de366004613428565b611200565b6104176104f1366004613428565b61129f565b61041761050436600461340f565b611303565b600b5461051c906001600160a01b031681565b6040516001600160a01b0390911681526020016103e6565b600154600160a01b900460ff1660405190151581526020016103e6565b6103dc61055f3660046133f4565b600e6020526000908152604090205481565b6103dc611364565b6103dc600d5481565b6104176113b0565b6103dc6105983660046133f4565b6001600160a01b031660009081526017602052604090205490565b6104176114a2565b60035461051c906001600160a01b031681565b6104176105dc366004613528565b6114f4565b6104176105ef36600461358c565b61154a565b6103dc60055481565b6103dc611613565b610417611621565b61041761061b366004613428565b611629565b6103dc61062e3660046133f4565b60096020526000908152604090205481565b61041761064e36600461358c565b61175a565b6001546001600160a01b031661051c565b6103dc61067236600461340f565b6117a2565b6104176106853660046135b8565b6117b2565b6104176106983660046135b8565b6118c9565b6104176106ab3660046133f4565b6119e0565b6103dc6106be366004613428565b611b8b565b6104176106d136600461340f565b611c3a565b6103dc600c5481565b6103dc6106ed3660046133f4565b60146020526000908152604090205481565b6103dc60075481565b61041761071636600461340f565b611e64565b6103dc611f55565b610417611f9b565b60025461051c906001600160a01b031681565b6103dc60115481565b61041761075536600461340f565b612050565b6103dc60085481565b61041761209d565b610417610779366004613428565b6120ce565b6103dc60045481565b610417610795366004613661565b612132565b6103dc6107a83660046133f4565b600f6020526000908152604090205481565b6104176107c83660046133f4565b612414565b6103dc6124e1565b6104176107e33660046135b8565b6124fa565b610417612611565b6103dc6107fe3660046133f4565b60106020526000908152604090205481565b6001600160a01b0381166000908152600a60209081526040808320546009909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611f55565b9061282f565b6001600160a01b03881660009081526017602052604090205490612842565b9061284e565b9061285a565b92915050565b6001546001600160a01b031633146108db5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064015b60405180910390fd5b600154600160a01b900460ff16156109285760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b60045442106109a1576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f742073746f70207265776172647320656d697373696f6e7320696660448201527f206e6f742073746172746564206f7220616c72656164792066696e697368656460648201526084016108d2565b60008060165460001415610aaa576002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156109f7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1b91906136b0565b600b549092506001600160a01b031615610aa257600b546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9b91906136b0565b9050610ade565b506000610ade565b600454600090610aba904261282f565b600554909150610aca9082612842565b600c54909350610ada9082612842565b9150505b426004558115610b1057610b10610afd6001546001600160a01b031690565b6002546001600160a01b03169084612866565b600b546001600160a01b031615801590610b2a5750600081115b15610b5757610b57610b446001546001600160a01b031690565b600b546001600160a01b03169083612866565b610b5f61290f565b6040518281527f6d815f6a8a51efb6f4140923189859b9e9caaa228c9334179e8eb7edefc6838e906020015b60405180910390a15050565b6001600160a01b038116600090815260176020526040812054610888908390611b8b565b6000610bd460065460055461284290919063ffffffff16565b905090565b60026000541415610c2c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610c3a611f55565b600855610c45611364565b600d55610c50611613565b6007556001600160a01b03811615610ccb57610c6b81610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610c9f8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600b546001600160a01b031615610d5457336000908152600f60205260409020548015610d5257336000818152600f6020526040812055600b54610d1b916001600160a01b039091169083612866565b60405181815233907fd1e5531ac01ffc9c7971b52c82806a6e5ae8907ddedd2e3153afaafcfdf175d6906020015b60405180910390a25b505b506001600055565b6001546001600160a01b03163314610da45760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b601654158015610dc457506003546002546001600160a01b039081169116145b610e5c5760405162461bcd60e51b815260206004820152605e60248201527f43616e6e6f74207265636f766572206c6566746f76657220726577617264206960448201527f66206974206973206e6f7420746865207374616b696e6720746f6b656e206f7260648201527f20746865726520617265207374696c6c207374616b656420746f6b656e730000608482015260a4016108d2565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec991906136b0565b90508015610ef957610ef9610ee66001546001600160a01b031690565b6002546001600160a01b03169083612866565b6040518181527ff6d91c6a1bf05d7c0f2c157905a97d3bc2f860a1402d71dd52a27fabb5bcaf8d906020015b60405180910390a150565b60026000541415610f835760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610f91611f55565b600855610f9c611364565b600d55610fa7611613565b6007556001600160a01b0381161561102257610fc281610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610ff68161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b610d52826129b4565b6012818154811061103b57600080fd5b600091825260209091200154905081565b6001600160a01b0381166000908152600f6020908152604080832054600e909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611364565b600260005414156110e65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055336110f4611f55565b6008556110ff611364565b600d5561110a611613565b6007556001600160a01b038116156111855761112581610810565b6001600160a01b0382166000908152600a60209081526040808320939093556008546009909152919020556111598161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b336000908152600a60205260409020548015610d5257336000818152600a60205260408120556002546111c4916001600160a01b039091169083612866565b60405181815233907fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048690602001610d49565b6111fe612af9565b565b6001546001600160a01b031633146112485760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b03821660009081526010602052604090205460115461126d9161282f565b60119081556001600160a01b038316600090815260106020526040902082905554611298908261285a565b6011555050565b6001546001600160a01b031633146112e75760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b039091166000908152600f6020526040902055565b600260005414156113565760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055610d54816129b4565b6000601654600014156113785750600d5490565b610bd46113a760165461087c670de0b6b3a76400006113a1600c546113a1600754610857611613565b90612842565b600d549061285a565b600260005414156114035760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b60026000908155338152601060205260409020548015610d5457336000908152601060205260409020546011546114399161282f565b60115533600081815260106020526040812055600254611465916001600160a01b039091169083612866565b60405181815233907fef4696bdcf47e292773442e4169d670e1b2d0d3f5ceff2a5c1e236c10109ee809060200160405180910390a2506001600055565b6001546001600160a01b031633146114ea5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6111fe6000612b86565b6001546001600160a01b0316331461153c5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6115468282612be5565b5050565b6001546001600160a01b031633146115925760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6115bb6115a76001546001600160a01b031690565b6002546001600160a01b0316903086612cb7565b600b546001600160a01b0316158015906115d55750600082115b15611603576116036115ef6001546001600160a01b031690565b600b546001600160a01b0316903085612cb7565b61160e838383612d0e565b505050565b6000610bd4426004546130b9565b6111fe61290f565b6001546001600160a01b031633146116715760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6003546001600160a01b03838116911614156116f55760405162461bcd60e51b815260206004820152602160248201527f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560448201527f6e0000000000000000000000000000000000000000000000000000000000000060648201526084016108d2565b61171b61170a6001546001600160a01b031690565b6001600160a01b0384169083612866565b604080516001600160a01b0384168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa289101610b8b565b6001546001600160a01b031633146116035760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6013818154811061103b57600080fd5b6001546001600160a01b031633146117fa5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146118715760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576118b9838281518110611892576118926136c9565b60200260200101518383815181106118ac576118ac6136c9565b6020026020010151611200565b6118c2816136f5565b9050611874565b6001546001600160a01b031633146119115760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146119885760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576119d08382815181106119a9576119a96136c9565b60200260200101518383815181106119c3576119c36136c9565b60200260200101516120ce565b6119d9816136f5565b905061198b565b6001546001600160a01b03163314611a285760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6002546001600160a01b0382811691161415611aac5760405162461bcd60e51b815260206004820152603960248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d207468652072657761726420746f6b656e0000000000000060648201526084016108d2565b6003546001600160a01b0382811691161415611b305760405162461bcd60e51b815260206004820152603a60248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d20746865207374616b696e6720746f6b656e00000000000060648201526084016108d2565b600b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f0c6fec5b80219c372da56cb4d1ef3e172069953fa5c72ececf0d0dfe1109260b90602001610f25565b6000805b601254811015611c305760128181548110611bac57611bac6136c9565b60009182526020808320909101546001600160a01b03871683526014909152604090912054611bdc90429061282f565b1015611c2057611c186103e861087c60138481548110611bfe57611bfe6136c9565b90600052602060002001548661284290919063ffffffff16565b915050610888565b611c29816136f5565b9050611b8f565b5060009392505050565b60026000541415611c8d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff1615611cdf5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b33611ce8611f55565b600855611cf3611364565b600d55611cfe611613565b6007556001600160a01b03811615611d7957611d1981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055611d4d8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b60008211611dc95760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b601654611dd6908361285a565b60165533600090815260176020526040902054611df3908361285a565b33600081815260176020526040902091909155600354611e20916001600160a01b03909116903085612cb7565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d90610d499085815260200190565b6001546001600160a01b03163314611eac5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6004544211611f495760405162461bcd60e51b815260206004820152605860248201527f50726576696f7573207265776172647320706572696f64206d7573742062652060448201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260648201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000608482015260a4016108d2565b611f52816130cf565b50565b600060165460001415611f69575060085490565b610bd4611f9260165461087c670de0b6b3a76400006113a16005546113a1600754610857611613565b6008549061285a565b6001546001600160a01b03163314611fe35760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b61200e611ff86001546001600160a01b031690565b6015546003546001600160a01b03169190612866565b7f6857c770f3cb43e9c19050a37dd914ec876241c1f4b487d26a1d4f5d3054f49b60155460405161204191815260200190565b60405180910390a16000601555565b6001546001600160a01b031633146120985760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b600755565b336000908152601760205260409020546120b690610f30565b6120be611093565b6120c6610bd9565b6111fe6113b0565b6001546001600160a01b031633146121165760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b039091166000908152600a6020526040902055565b600260005414156121855760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff16156121d75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b336121e0611f55565b6008556121eb611364565b600d556121f6611613565b6007556001600160a01b038116156122715761221181610810565b6001600160a01b0382166000908152600a60209081526040808320939093556008546009909152919020556122458161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600086116122c15760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b6016546122ce908761285a565b601655336000908152601760205260409020546122eb908761285a565b33600081815260176020526040908190209290925560035491517fd505accf0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c481018490526001600160a01b039091169063d505accf9060e401600060405180830381600087803b15801561238a57600080fd5b505af115801561239e573d6000803e3d6000fd5b50506003546123bb92506001600160a01b03169050333089612cb7565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906123ff9089815260200190565b60405180910390a25050600160005550505050565b6001546001600160a01b0316331461245c5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b0381166124d85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016108d2565b611f5281612b86565b6000610bd4600654600c5461284290919063ffffffff16565b6001546001600160a01b031633146125425760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146125b95760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576126018382815181106125da576125da6136c9565b60200260200101518383815181106125f4576125f46136c9565b602002602001015161129f565b61260a816136f5565b90506125bc565b6001546001600160a01b031633146126595760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b600b546001600160a01b03166126fd5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520776173206e6f20626f6f7374657220746f6b656e20736560648201527f7400000000000000000000000000000000000000000000000000000000000000608482015260a4016108d2565b60165415612775576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520617265207374696c6c207374616b656420746f6b656e7360648201526084016108d2565b600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e291906136b0565b905080156127ff576127ff610b446001546001600160a01b031690565b6040518181527fa075ee3dcd38efb87f0f97160a935b6a43768378263338beea06b9681f66151d90602001610f25565b600061283b8284613710565b9392505050565b600061283b8284613727565b600061283b8284613746565b600061283b8284613768565b6040516001600160a01b03831660248201526044810182905261160e9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613104565b600154600160a01b900460ff161561295c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129973390565b6040516001600160a01b03909116815260200160405180910390a1565b60008111612a045760405162461bcd60e51b815260206004820152601160248201527f43616e6e6f74207769746864726177203000000000000000000000000000000060448201526064016108d2565b601654612a11908261282f565b6016556000612a203383611b8b565b33600090815260176020526040902054909150612a3d908361282f565b33600090815260176020526040812091909155612a5a838361282f565b600354909150612a74906001600160a01b03163383612866565b60405181815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d59060200160405180910390a2811561160e5760405182815233907f9dc46f23cfb5ddcad0ae7ea2be38d47fec07bb9382ec7e564efc69e036dd66ce9060200160405180910390a2601554612af1908361285a565b601555505050565b600154600160a01b900460ff16612b525760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016108d2565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612997565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8051825114612c5e576040805162461bcd60e51b81526020600482015260248101919091527f466565207363686564756c6520616e64207769746864726177616c206665657360448201527f20617272617973206d757374206265207468652073616d65206c656e6774682160648201526084016108d2565b8151612c71906012906020850190613378565b508051612c85906013906020840190613378565b507fe5a2c1e4acf2a2da539a1183c56fbbcec4b66dbc828b76f1c1bf365f1887886b8282604051610b8b9291906137bb565b6040516001600160a01b0380851660248301528316604482015260648101829052612d089085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016128ab565b50505050565b6000612d18611f55565b600855612d23611364565b600d55612d2e611613565b6007556001600160a01b03811615612da957612d4981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055612d7d8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b8115612db857612db8826130cf565b6004544210612de857600654612dcf90859061284e565b600555600654612de090849061284e565b600c55612e54565b600454600090612df8904261282f565b90506000612e116005548361284290919063ffffffff16565b600654909150612e259061087c888461285a565b600555600c54600090612e39908490612842565b600654909150612e4d9061087c888461285a565b600c555050505b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec191906136b0565b9050612ed86006548261284e90919063ffffffff16565b600554111580612f1f57506003546002546001600160a01b039081169116148015612f1f5750612f196016546108576006548461284e90919063ffffffff16565b60055411155b612f6b5760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f2068696768000000000000000060448201526064016108d2565b600b546001600160a01b03161561305357600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612fc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe991906136b0565b90506130006006548261284e90919063ffffffff16565b600c5411156130515760405162461bcd60e51b815260206004820181905260248201527f50726f766964656420626f6f737465722072657761726420746f6f206869676860448201526064016108d2565b505b426007819055600654613066919061285a565b600455613071612af9565b60408051868152602081018690529081018490527f748824204e79acdab8f1a9977cbc584250e206ad90d05ef198799f9d6ee93a7d9060600160405180910390a15050505050565b60008183106130c8578161283b565b5090919050565b60068190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610f25565b6000613159826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131e99092919063ffffffff16565b80519091501561160e578080602001905181019061317791906137e9565b61160e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108d2565b60606131f88484600085613200565b949350505050565b6060824710156132785760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016108d2565b843b6132c65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d2565b600080866001600160a01b031685876040516132e29190613837565b60006040518083038185875af1925050503d806000811461331f576040519150601f19603f3d011682016040523d82523d6000602084013e613324565b606091505b509150915061333482828661333f565b979650505050505050565b6060831561334e57508161283b565b82511561335e5782518084602001fd5b8160405162461bcd60e51b81526004016108d29190613853565b8280548282559060005260206000209081019282156133b3579160200282015b828111156133b3578251825591602001919060010190613398565b506133bf9291506133c3565b5090565b5b808211156133bf57600081556001016133c4565b80356001600160a01b03811681146133ef57600080fd5b919050565b60006020828403121561340657600080fd5b61283b826133d8565b60006020828403121561342157600080fd5b5035919050565b6000806040838503121561343b57600080fd5b613444836133d8565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561349157613491613452565b604052919050565b600067ffffffffffffffff8211156134b3576134b3613452565b5060051b60200190565b600082601f8301126134ce57600080fd5b813560206134e36134de83613499565b613468565b82815260059290921b8401810191818101908684111561350257600080fd5b8286015b8481101561351d5780358352918301918301613506565b509695505050505050565b6000806040838503121561353b57600080fd5b823567ffffffffffffffff8082111561355357600080fd5b61355f868387016134bd565b9350602085013591508082111561357557600080fd5b50613582858286016134bd565b9150509250929050565b6000806000606084860312156135a157600080fd5b505081359360208301359350604090920135919050565b600080604083850312156135cb57600080fd5b823567ffffffffffffffff808211156135e357600080fd5b818501915085601f8301126135f757600080fd5b813560206136076134de83613499565b82815260059290921b8401810191818101908984111561362657600080fd5b948201945b8386101561364b5761363c866133d8565b8252948201949082019061362b565b9650508601359250508082111561357557600080fd5b600080600080600060a0868803121561367957600080fd5b8535945060208601359350604086013560ff8116811461369857600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156136c257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613709576137096136df565b5060010190565b600082821015613722576137226136df565b500390565b6000816000190483118215151615613741576137416136df565b500290565b60008261376357634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561377b5761377b6136df565b500190565b600081518084526020808501945080840160005b838110156137b057815187529582019590820190600101613794565b509495945050505050565b6040815260006137ce6040830185613780565b82810360208401526137e08185613780565b95945050505050565b6000602082840312156137fb57600080fd5b8151801515811461283b57600080fd5b60005b8381101561382657818101518382015260200161380e565b83811115612d085750506000910152565b6000825161384981846020870161380b565b9190910192915050565b602081526000825180602084015261387281604085016020870161380b565b601f01601f1916919091016040019291505056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220362c2bfa3419b92432acb1e48c03aab4e6617c26e4c399ff72ecafc77942c73364736f6c634300080a0033