Contract Address Details

0x59d39bC9b0B36306b36895017A56B40eCC98D1d9

Contract Name
StakingRewards
Creator
0xaef263–bdc888 at 0xfb102a–fe66b1
Balance
0 ELA
Tokens
Fetching tokens...
Transactions
Transfers
Gas Used
Last Balance Update
28287587
Contract name:
StakingRewards




Optimization enabled
true
Compiler version
v0.8.9+commit.e5eed63a




Optimization runs
1000
EVM Version
default




Verified at
2021-10-31 22:16:29.714299Z

Constructor Arguments

000000000000000000000000e1c110e1b1b4a1ded0caf3e42bfbdbb7b5d7ce1c000000000000000000000000e1c110e1b1b4a1ded0caf3e42bfbdbb7b5d7ce1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000375f0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000e100000000000000000000000000000000000000000000000000000000000093a800000000000000000000000000000000000000000000000000000000000278d00000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000a
              

Contract source code

// Sources flattened with hardhat v2.6.2 https://hardhat.org
// File @openzeppelin/contracts/utils/[email protected]
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/access/[email protected]
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 @openzeppelin/contracts/utils/math/[email protected]
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/utils/math/[email protected]
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/security/[email protected]
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/security/[email protected]
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/token/ERC20/[email protected]
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/utils/[email protected]
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/token/ERC20/utils/[email protected]
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 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 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 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"}]}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106103c45760003560e01c806380faa57d116101ff578063cd3daf9d1161011a578063ebe2b12b116100ad578063f3f0ffda1161007c578063f3f0ffda146107cd578063f86e55ca146107d5578063faef375e146107e8578063ffb13208146107f057600080fd5b8063ebe2b12b1461077e578063ecd9ba8214610787578063f22797d81461079a578063f2fde38b146107ba57600080fd5b8063d9142bbe116100e9578063d9142bbe14610747578063df136d651461075a578063e9fad8ee14610763578063eacccaf01461076b57600080fd5b8063cd3daf9d1461071b578063cdeae37114610723578063d1af0c7d1461072b578063d51942e21461073e57600080fd5b80639292052211610192578063be0bf75111610161578063be0bf751146106d6578063c57a202c146106df578063c8f33c91146106ff578063cc1a378f1461070857600080fd5b8063929205221461068a5780639465d4a11461069d5780639e6eda18146106b0578063a694fc3a146106c357600080fd5b80638bb95b45116101ce5780638bb95b45146106405780638da5cb5b146106535780638f0bb79c14610664578063905b7d3c1461067757600080fd5b806380faa57d146105fd5780638456cb59146106055780638980f11f1461060d5780638b8763471461062057600080fd5b80633f4ba83a116102ef57806366a03c7f1161028257806372f702f31161025157806372f702f3146105bb57806377075130146105ce57806377191605146105e15780637b0a47ee146105f457600080fd5b806366a03c7f146105795780636de4ab871461058257806370a082311461058a578063715018a6146105b357600080fd5b8063576c23ab116102be578063576c23ab146105095780635c975abb146105345780635d129544146105515780636439ea4c1461057157600080fd5b80633f4ba83a146104c857806343d45c17146104d05780634b03f2e9146104e35780635312ea8e146104f657600080fd5b80631c1f78eb1161036757806335ceec0f1161033657806335ceec0f14610491578063386a9525146104a45780633b8e4f7e146104ad5780633d18b912146104c057600080fd5b80631c1f78eb146104665780632459a6991461046e5780632cbe61d3146104765780632e1a7d4d1461047e57600080fd5b806310cbbe38116103a357806310cbbe3814610419578063120459871461042c57806313114a9d1461045557806318160ddd1461045e57600080fd5b80628cc262146103c95780630700037d146103ef5780630e9bb0a31461040f575b600080fd5b6103dc6103d7366004613401565b610810565b6040519081526020015b60405180910390f35b6103dc6103fd366004613401565b600a6020526000908152604090205481565b61041761088e565b005b6103dc610427366004613401565b610bb5565b6103dc61043a366004613401565b6001600160a01b031660009081526010602052604090205490565b6103dc60155481565b6016546103dc565b6103dc610bd9565b610417610bf7565b610417610d7a565b61041761048c36600461341c565b610f5d565b6103dc61049f36600461341c565b611058565b6103dc60065481565b6103dc6104bb366004613401565b611079565b6104176110c0565b610417611223565b6104176104de366004613435565b61122d565b6104176104f1366004613435565b6112cc565b61041761050436600461341c565b611330565b600b5461051c906001600160a01b031681565b6040516001600160a01b0390911681526020016103e6565b600154600160a01b900460ff1660405190151581526020016103e6565b6103dc61055f366004613401565b600e6020526000908152604090205481565b6103dc611391565b6103dc600d5481565b6104176113dd565b6103dc610598366004613401565b6001600160a01b031660009081526017602052604090205490565b6104176114cf565b60035461051c906001600160a01b031681565b6104176105dc366004613535565b611521565b6104176105ef366004613599565b611577565b6103dc60055481565b6103dc611640565b61041761164e565b61041761061b366004613435565b611656565b6103dc61062e366004613401565b60096020526000908152604090205481565b61041761064e366004613599565b611787565b6001546001600160a01b031661051c565b6103dc61067236600461341c565b6117cf565b6104176106853660046135c5565b6117df565b6104176106983660046135c5565b6118f6565b6104176106ab366004613401565b611a0d565b6103dc6106be366004613435565b611bb8565b6104176106d136600461341c565b611c67565b6103dc600c5481565b6103dc6106ed366004613401565b60146020526000908152604090205481565b6103dc60075481565b61041761071636600461341c565b611e91565b6103dc611f82565b610417611fc8565b60025461051c906001600160a01b031681565b6103dc60115481565b61041761075536600461341c565b61207d565b6103dc60085481565b6104176120ca565b610417610779366004613435565b6120fb565b6103dc60045481565b61041761079536600461366e565b61215f565b6103dc6107a8366004613401565b600f6020526000908152604090205481565b6104176107c8366004613401565b6123f4565b6103dc6124c1565b6104176107e33660046135c5565b6124da565b6104176125f1565b6103dc6107fe366004613401565b60106020526000908152604090205481565b6001600160a01b0381166000908152600a60209081526040808320546009909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611f82565b9061281e565b6001600160a01b03881660009081526017602052604090205490612831565b9061283d565b90612849565b92915050565b6001546001600160a01b031633146108db5760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064015b60405180910390fd5b600154600160a01b900460ff16156109285760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b60045442106109a1576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f742073746f70207265776172647320656d697373696f6e7320696660448201527f206e6f742073746172746564206f7220616c72656164792066696e697368656460648201526084016108d2565b60008060165460001415610ac8576002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b1580156109f257600080fd5b505afa158015610a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2a91906136bd565b600b549092506001600160a01b031615610ac057600b546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610a8157600080fd5b505afa158015610a95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab991906136bd565b9050610afc565b506000610afc565b600454600090610ad8904261281e565b600554909150610ae89082612831565b600c54909350610af89082612831565b9150505b426004558115610b2e57610b2e610b1b6001546001600160a01b031690565b6002546001600160a01b03169084612855565b600b546001600160a01b031615801590610b485750600081115b15610b7557610b75610b626001546001600160a01b031690565b600b546001600160a01b03169083612855565b610b7d6128fe565b6040518281527f6d815f6a8a51efb6f4140923189859b9e9caaa228c9334179e8eb7edefc6838e906020015b60405180910390a15050565b6001600160a01b038116600090815260176020526040812054610888908390611bb8565b6000610bf260065460055461283190919063ffffffff16565b905090565b60026000541415610c4a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610c58611f82565b600855610c63611391565b600d55610c6e611640565b6007556001600160a01b03811615610ce957610c8981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610cbd81611079565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600b546001600160a01b031615610d7257336000908152600f60205260409020548015610d7057336000818152600f6020526040812055600b54610d39916001600160a01b039091169083612855565b60405181815233907fd1e5531ac01ffc9c7971b52c82806a6e5ae8907ddedd2e3153afaafcfdf175d6906020015b60405180910390a25b505b506001600055565b6001546001600160a01b03163314610dc25760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b601654158015610de257506003546002546001600160a01b039081169116145b610e7a5760405162461bcd60e51b815260206004820152605e60248201527f43616e6e6f74207265636f766572206c6566746f76657220726577617264206960448201527f66206974206973206e6f7420746865207374616b696e6720746f6b656e206f7260648201527f20746865726520617265207374696c6c207374616b656420746f6b656e730000608482015260a4016108d2565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015610ebe57600080fd5b505afa158015610ed2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef691906136bd565b90508015610f2657610f26610f136001546001600160a01b031690565b6002546001600160a01b03169083612855565b6040518181527ff6d91c6a1bf05d7c0f2c157905a97d3bc2f860a1402d71dd52a27fabb5bcaf8d906020015b60405180910390a150565b60026000541415610fb05760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610fbe611f82565b600855610fc9611391565b600d55610fd4611640565b6007556001600160a01b0381161561104f57610fef81610810565b6001600160a01b0382166000908152600a602090815260408083209390935560085460099091529190205561102381611079565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b610d70826129a3565b6012818154811061106857600080fd5b600091825260209091200154905081565b6001600160a01b0381166000908152600f6020908152604080832054600e909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611391565b600260005414156111135760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533611121611f82565b60085561112c611391565b600d55611137611640565b6007556001600160a01b038116156111b25761115281610810565b6001600160a01b0382166000908152600a602090815260408083209390935560085460099091529190205561118681611079565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b336000908152600a60205260409020548015610d7057336000818152600a60205260408120556002546111f1916001600160a01b039091169083612855565b60405181815233907fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048690602001610d67565b61122b612ae8565b565b6001546001600160a01b031633146112755760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6001600160a01b03821660009081526010602052604090205460115461129a9161281e565b60119081556001600160a01b0383166000908152601060205260409020829055546112c59082612849565b6011555050565b6001546001600160a01b031633146113145760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6001600160a01b039091166000908152600f6020526040902055565b600260005414156113835760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055610d72816129a3565b6000601654600014156113a55750600d5490565b610bf26113d460165461087c670de0b6b3a76400006113ce600c546113ce600754610857611640565b90612831565b600d5490612849565b600260005414156114305760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b60026000908155338152601060205260409020548015610d7257336000908152601060205260409020546011546114669161281e565b60115533600081815260106020526040812055600254611492916001600160a01b039091169083612855565b60405181815233907fef4696bdcf47e292773442e4169d670e1b2d0d3f5ceff2a5c1e236c10109ee809060200160405180910390a2506001600055565b6001546001600160a01b031633146115175760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b61122b6000612b75565b6001546001600160a01b031633146115695760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6115738282612bd4565b5050565b6001546001600160a01b031633146115bf5760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6115e86115d46001546001600160a01b031690565b6002546001600160a01b0316903086612ca6565b600b546001600160a01b0316158015906116025750600082115b156116305761163061161c6001546001600160a01b031690565b600b546001600160a01b0316903085612ca6565b61163b838383612cfd565b505050565b6000610bf2426004546130c6565b61122b6128fe565b6001546001600160a01b0316331461169e5760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6003546001600160a01b03838116911614156117225760405162461bcd60e51b815260206004820152602160248201527f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560448201527f6e0000000000000000000000000000000000000000000000000000000000000060648201526084016108d2565b6117486117376001546001600160a01b031690565b6001600160a01b0384169083612855565b604080516001600160a01b0384168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa289101610ba9565b6001546001600160a01b031633146116305760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6013818154811061106857600080fd5b6001546001600160a01b031633146118275760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b805182511461189e5760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561163b576118e68382815181106118bf576118bf6136d6565b60200260200101518383815181106118d9576118d96136d6565b602002602001015161122d565b6118ef81613702565b90506118a1565b6001546001600160a01b0316331461193e5760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b80518251146119b55760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561163b576119fd8382815181106119d6576119d66136d6565b60200260200101518383815181106119f0576119f06136d6565b60200260200101516120fb565b611a0681613702565b90506119b8565b6001546001600160a01b03163314611a555760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6002546001600160a01b0382811691161415611ad95760405162461bcd60e51b815260206004820152603960248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d207468652072657761726420746f6b656e0000000000000060648201526084016108d2565b6003546001600160a01b0382811691161415611b5d5760405162461bcd60e51b815260206004820152603a60248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d20746865207374616b696e6720746f6b656e00000000000060648201526084016108d2565b600b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f0c6fec5b80219c372da56cb4d1ef3e172069953fa5c72ececf0d0dfe1109260b90602001610f52565b6000805b601254811015611c5d5760128181548110611bd957611bd96136d6565b60009182526020808320909101546001600160a01b03871683526014909152604090912054611c0990429061281e565b1015611c4d57611c456103e861087c60138481548110611c2b57611c2b6136d6565b90600052602060002001548661283190919063ffffffff16565b915050610888565b611c5681613702565b9050611bbc565b5060009392505050565b60026000541415611cba5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff1615611d0c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b33611d15611f82565b600855611d20611391565b600d55611d2b611640565b6007556001600160a01b03811615611da657611d4681610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055611d7a81611079565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b60008211611df65760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b601654611e039083612849565b60165533600090815260176020526040902054611e209083612849565b33600081815260176020526040902091909155600354611e4d916001600160a01b03909116903085612ca6565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d90610d679085815260200190565b6001546001600160a01b03163314611ed95760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6004544211611f765760405162461bcd60e51b815260206004820152605860248201527f50726576696f7573207265776172647320706572696f64206d7573742062652060448201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260648201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000608482015260a4016108d2565b611f7f816130dc565b50565b600060165460001415611f96575060085490565b610bf2611fbf60165461087c670de0b6b3a76400006113ce6005546113ce600754610857611640565b60085490612849565b6001546001600160a01b031633146120105760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b61203b6120256001546001600160a01b031690565b6015546003546001600160a01b03169190612855565b7f6857c770f3cb43e9c19050a37dd914ec876241c1f4b487d26a1d4f5d3054f49b60155460405161206e91815260200190565b60405180910390a16000601555565b6001546001600160a01b031633146120c55760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b600755565b336000908152601760205260409020546120e390610f5d565b6120eb6110c0565b6120f3610bf7565b61122b6113dd565b6001546001600160a01b031633146121435760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6001600160a01b039091166000908152600a6020526040902055565b600260005414156121b25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055336121c0611f82565b6008556121cb611391565b600d556121d6611640565b6007556001600160a01b03811615612251576121f181610810565b6001600160a01b0382166000908152600a602090815260408083209390935560085460099091529190205561222581611079565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600086116122a15760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b6016546122ae9087612849565b601655336000908152601760205260409020546122cb9087612849565b33600081815260176020526040908190209290925560035491517fd505accf0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c481018490526001600160a01b039091169063d505accf9060e401600060405180830381600087803b15801561236a57600080fd5b505af115801561237e573d6000803e3d6000fd5b505060035461239b92506001600160a01b03169050333089612ca6565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906123df9089815260200190565b60405180910390a25050600160005550505050565b6001546001600160a01b0316331461243c5760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b6001600160a01b0381166124b85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016108d2565b611f7f81612b75565b6000610bf2600654600c5461283190919063ffffffff16565b6001546001600160a01b031633146125225760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b80518251146125995760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561163b576125e18382815181106125ba576125ba6136d6565b60200260200101518383815181106125d4576125d46136d6565b60200260200101516112cc565b6125ea81613702565b905061259c565b6001546001600160a01b031633146126395760405162461bcd60e51b8152602060048201819052602482015260008051602061389483398151915260448201526064016108d2565b600b546001600160a01b03166126dd5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520776173206e6f20626f6f7374657220746f6b656e20736560648201527f7400000000000000000000000000000000000000000000000000000000000000608482015260a4016108d2565b60165415612755576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520617265207374696c6c207374616b656420746f6b656e7360648201526084016108d2565b600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b15801561279957600080fd5b505afa1580156127ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d191906136bd565b905080156127ee576127ee610b626001546001600160a01b031690565b6040518181527fa075ee3dcd38efb87f0f97160a935b6a43768378263338beea06b9681f66151d90602001610f52565b600061282a828461371d565b9392505050565b600061282a8284613734565b600061282a8284613753565b600061282a8284613775565b6040516001600160a01b03831660248201526044810182905261163b9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613111565b600154600160a01b900460ff161561294b5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129863390565b6040516001600160a01b03909116815260200160405180910390a1565b600081116129f35760405162461bcd60e51b815260206004820152601160248201527f43616e6e6f74207769746864726177203000000000000000000000000000000060448201526064016108d2565b601654612a00908261281e565b6016556000612a0f3383611bb8565b33600090815260176020526040902054909150612a2c908361281e565b33600090815260176020526040812091909155612a49838361281e565b600354909150612a63906001600160a01b03163383612855565b60405181815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d59060200160405180910390a2811561163b5760405182815233907f9dc46f23cfb5ddcad0ae7ea2be38d47fec07bb9382ec7e564efc69e036dd66ce9060200160405180910390a2601554612ae09083612849565b601555505050565b600154600160a01b900460ff16612b415760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016108d2565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612986565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8051825114612c4d576040805162461bcd60e51b81526020600482015260248101919091527f466565207363686564756c6520616e64207769746864726177616c206665657360448201527f20617272617973206d757374206265207468652073616d65206c656e6774682160648201526084016108d2565b8151612c60906012906020850190613385565b508051612c74906013906020840190613385565b507fe5a2c1e4acf2a2da539a1183c56fbbcec4b66dbc828b76f1c1bf365f1887886b8282604051610ba99291906137c8565b6040516001600160a01b0380851660248301528316604482015260648101829052612cf79085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161289a565b50505050565b6000612d07611f82565b600855612d12611391565b600d55612d1d611640565b6007556001600160a01b03811615612d9857612d3881610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055612d6c81611079565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b8115612da757612da7826130dc565b6004544210612dd757600654612dbe90859061283d565b600555600654612dcf90849061283d565b600c55612e43565b600454600090612de7904261281e565b90506000612e006005548361283190919063ffffffff16565b600654909150612e149061087c8884612849565b600555600c54600090612e28908490612831565b600654909150612e3c9061087c8884612849565b600c555050505b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015612e8757600080fd5b505afa158015612e9b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ebf91906136bd565b9050612ed66006548261283d90919063ffffffff16565b600554111580612f1d57506003546002546001600160a01b039081169116148015612f1d5750612f176016546108576006548461283d90919063ffffffff16565b60055411155b612f695760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f2068696768000000000000000060448201526064016108d2565b600b546001600160a01b03161561306057600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240160206040518083038186803b158015612fbe57600080fd5b505afa158015612fd2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ff691906136bd565b905061300d6006548261283d90919063ffffffff16565b600c54111561305e5760405162461bcd60e51b815260206004820181905260248201527f50726f766964656420626f6f737465722072657761726420746f6f206869676860448201526064016108d2565b505b4260078190556006546130739190612849565b60045561307e612ae8565b60408051868152602081018690529081018490527f748824204e79acdab8f1a9977cbc584250e206ad90d05ef198799f9d6ee93a7d9060600160405180910390a15050505050565b60008183106130d5578161282a565b5090919050565b60068190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610f52565b6000613166826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131f69092919063ffffffff16565b80519091501561163b578080602001905181019061318491906137f6565b61163b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108d2565b6060613205848460008561320d565b949350505050565b6060824710156132855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016108d2565b843b6132d35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d2565b600080866001600160a01b031685876040516132ef9190613844565b60006040518083038185875af1925050503d806000811461332c576040519150601f19603f3d011682016040523d82523d6000602084013e613331565b606091505b509150915061334182828661334c565b979650505050505050565b6060831561335b57508161282a565b82511561336b5782518084602001fd5b8160405162461bcd60e51b81526004016108d29190613860565b8280548282559060005260206000209081019282156133c0579160200282015b828111156133c05782518255916020019190600101906133a5565b506133cc9291506133d0565b5090565b5b808211156133cc57600081556001016133d1565b80356001600160a01b03811681146133fc57600080fd5b919050565b60006020828403121561341357600080fd5b61282a826133e5565b60006020828403121561342e57600080fd5b5035919050565b6000806040838503121561344857600080fd5b613451836133e5565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561349e5761349e61345f565b604052919050565b600067ffffffffffffffff8211156134c0576134c061345f565b5060051b60200190565b600082601f8301126134db57600080fd5b813560206134f06134eb836134a6565b613475565b82815260059290921b8401810191818101908684111561350f57600080fd5b8286015b8481101561352a5780358352918301918301613513565b509695505050505050565b6000806040838503121561354857600080fd5b823567ffffffffffffffff8082111561356057600080fd5b61356c868387016134ca565b9350602085013591508082111561358257600080fd5b5061358f858286016134ca565b9150509250929050565b6000806000606084860312156135ae57600080fd5b505081359360208301359350604090920135919050565b600080604083850312156135d857600080fd5b823567ffffffffffffffff808211156135f057600080fd5b818501915085601f83011261360457600080fd5b813560206136146134eb836134a6565b82815260059290921b8401810191818101908984111561363357600080fd5b948201945b8386101561365857613649866133e5565b82529482019490820190613638565b9650508601359250508082111561358257600080fd5b600080600080600060a0868803121561368657600080fd5b8535945060208601359350604086013560ff811681146136a557600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156136cf57600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613716576137166136ec565b5060010190565b60008282101561372f5761372f6136ec565b500390565b600081600019048311821515161561374e5761374e6136ec565b500290565b60008261377057634e487b7160e01b600052601260045260246000fd5b500490565b60008219821115613788576137886136ec565b500190565b600081518084526020808501945080840160005b838110156137bd578151875295820195908201906001016137a1565b509495945050505050565b6040815260006137db604083018561378d565b82810360208401526137ed818561378d565b95945050505050565b60006020828403121561380857600080fd5b8151801515811461282a57600080fd5b60005b8381101561383357818101518382015260200161381b565b83811115612cf75750506000910152565b60008251613856818460208701613818565b9190910192915050565b602081526000825180602084015261387f816040850160208701613818565b601f01601f1916919091016040019291505056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a26469706673582212209f1d3325810f3211ddd033523e40e3f2b54a3e20932835a31b4e2859240fb57f64736f6c63430008090033