Contract Address Details

0x5B0a0667635E12775AD897cbEAf105371D1f9eD1

Last Balance Update: Block #17926028
Created by 0xce024b–1624f2 at 0x390da6–9f1c93

Balance

0 Fuse

Fetching tokens...

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
Contract name:
StakingRewards




Optimization enabled
true
Compiler version
v0.8.10+commit.fc410830




Optimization runs
1000
Verified at
2021-12-18 05: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"}]}]
            

Deployed ByteCode

Verify & Publish
0x608060405234801561001057600080fd5b50600436106103c45760003560e01c806380faa57d116101ff578063cd3daf9d1161011a578063ebe2b12b116100ad578063f3f0ffda1161007c578063f3f0ffda146107cd578063f86e55ca146107d5578063faef375e146107e8578063ffb13208146107f057600080fd5b8063ebe2b12b1461077e578063ecd9ba8214610787578063f22797d81461079a578063f2fde38b146107ba57600080fd5b8063d9142bbe116100e9578063d9142bbe14610747578063df136d651461075a578063e9fad8ee14610763578063eacccaf01461076b57600080fd5b8063cd3daf9d1461071b578063cdeae37114610723578063d1af0c7d1461072b578063d51942e21461073e57600080fd5b80639292052211610192578063be0bf75111610161578063be0bf751146106d6578063c57a202c146106df578063c8f33c91146106ff578063cc1a378f1461070857600080fd5b8063929205221461068a5780639465d4a11461069d5780639e6eda18146106b0578063a694fc3a146106c357600080fd5b80638bb95b45116101ce5780638bb95b45146106405780638da5cb5b146106535780638f0bb79c14610664578063905b7d3c1461067757600080fd5b806380faa57d146105fd5780638456cb59146106055780638980f11f1461060d5780638b8763471461062057600080fd5b80633f4ba83a116102ef57806366a03c7f1161028257806372f702f31161025157806372f702f3146105bb57806377075130146105ce57806377191605146105e15780637b0a47ee146105f457600080fd5b806366a03c7f146105795780636de4ab871461058257806370a082311461058a578063715018a6146105b357600080fd5b8063576c23ab116102be578063576c23ab146105095780635c975abb146105345780635d129544146105515780636439ea4c1461057157600080fd5b80633f4ba83a146104c857806343d45c17146104d05780634b03f2e9146104e35780635312ea8e146104f657600080fd5b80631c1f78eb1161036757806335ceec0f1161033657806335ceec0f14610491578063386a9525146104a45780633b8e4f7e146104ad5780633d18b912146104c057600080fd5b80631c1f78eb146104665780632459a6991461046e5780632cbe61d3146104765780632e1a7d4d1461047e57600080fd5b806310cbbe38116103a357806310cbbe3814610419578063120459871461042c57806313114a9d1461045557806318160ddd1461045e57600080fd5b80628cc262146103c95780630700037d146103ef5780630e9bb0a31461040f575b600080fd5b6103dc6103d73660046133f4565b610810565b6040519081526020015b60405180910390f35b6103dc6103fd3660046133f4565b600a6020526000908152604090205481565b61041761088e565b005b6103dc6104273660046133f4565b610b97565b6103dc61043a3660046133f4565b6001600160a01b031660009081526010602052604090205490565b6103dc60155481565b6016546103dc565b6103dc610bbb565b610417610bd9565b610417610d5c565b61041761048c36600461340f565b610f30565b6103dc61049f36600461340f565b61102b565b6103dc60065481565b6103dc6104bb3660046133f4565b61104c565b610417611093565b6104176111f6565b6104176104de366004613428565b611200565b6104176104f1366004613428565b61129f565b61041761050436600461340f565b611303565b600b5461051c906001600160a01b031681565b6040516001600160a01b0390911681526020016103e6565b600154600160a01b900460ff1660405190151581526020016103e6565b6103dc61055f3660046133f4565b600e6020526000908152604090205481565b6103dc611364565b6103dc600d5481565b6104176113b0565b6103dc6105983660046133f4565b6001600160a01b031660009081526017602052604090205490565b6104176114a2565b60035461051c906001600160a01b031681565b6104176105dc366004613528565b6114f4565b6104176105ef36600461358c565b61154a565b6103dc60055481565b6103dc611613565b610417611621565b61041761061b366004613428565b611629565b6103dc61062e3660046133f4565b60096020526000908152604090205481565b61041761064e36600461358c565b61175a565b6001546001600160a01b031661051c565b6103dc61067236600461340f565b6117a2565b6104176106853660046135b8565b6117b2565b6104176106983660046135b8565b6118c9565b6104176106ab3660046133f4565b6119e0565b6103dc6106be366004613428565b611b8b565b6104176106d136600461340f565b611c3a565b6103dc600c5481565b6103dc6106ed3660046133f4565b60146020526000908152604090205481565b6103dc60075481565b61041761071636600461340f565b611e64565b6103dc611f55565b610417611f9b565b60025461051c906001600160a01b031681565b6103dc60115481565b61041761075536600461340f565b612050565b6103dc60085481565b61041761209d565b610417610779366004613428565b6120ce565b6103dc60045481565b610417610795366004613661565b612132565b6103dc6107a83660046133f4565b600f6020526000908152604090205481565b6104176107c83660046133f4565b612414565b6103dc6124e1565b6104176107e33660046135b8565b6124fa565b610417612611565b6103dc6107fe3660046133f4565b60106020526000908152604090205481565b6001600160a01b0381166000908152600a60209081526040808320546009909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611f55565b9061282f565b6001600160a01b03881660009081526017602052604090205490612842565b9061284e565b9061285a565b92915050565b6001546001600160a01b031633146108db5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064015b60405180910390fd5b600154600160a01b900460ff16156109285760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b60045442106109a1576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f742073746f70207265776172647320656d697373696f6e7320696660448201527f206e6f742073746172746564206f7220616c72656164792066696e697368656460648201526084016108d2565b60008060165460001415610aaa576002546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156109f7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a1b91906136b0565b600b549092506001600160a01b031615610aa257600b546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610a77573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9b91906136b0565b9050610ade565b506000610ade565b600454600090610aba904261282f565b600554909150610aca9082612842565b600c54909350610ada9082612842565b9150505b426004558115610b1057610b10610afd6001546001600160a01b031690565b6002546001600160a01b03169084612866565b600b546001600160a01b031615801590610b2a5750600081115b15610b5757610b57610b446001546001600160a01b031690565b600b546001600160a01b03169083612866565b610b5f61290f565b6040518281527f6d815f6a8a51efb6f4140923189859b9e9caaa228c9334179e8eb7edefc6838e906020015b60405180910390a15050565b6001600160a01b038116600090815260176020526040812054610888908390611b8b565b6000610bd460065460055461284290919063ffffffff16565b905090565b60026000541415610c2c5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610c3a611f55565b600855610c45611364565b600d55610c50611613565b6007556001600160a01b03811615610ccb57610c6b81610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610c9f8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600b546001600160a01b031615610d5457336000908152600f60205260409020548015610d5257336000818152600f6020526040812055600b54610d1b916001600160a01b039091169083612866565b60405181815233907fd1e5531ac01ffc9c7971b52c82806a6e5ae8907ddedd2e3153afaafcfdf175d6906020015b60405180910390a25b505b506001600055565b6001546001600160a01b03163314610da45760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b601654158015610dc457506003546002546001600160a01b039081169116145b610e5c5760405162461bcd60e51b815260206004820152605e60248201527f43616e6e6f74207265636f766572206c6566746f76657220726577617264206960448201527f66206974206973206e6f7420746865207374616b696e6720746f6b656e206f7260648201527f20746865726520617265207374696c6c207374616b656420746f6b656e730000608482015260a4016108d2565b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610ea5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec991906136b0565b90508015610ef957610ef9610ee66001546001600160a01b031690565b6002546001600160a01b03169083612866565b6040518181527ff6d91c6a1bf05d7c0f2c157905a97d3bc2f860a1402d71dd52a27fabb5bcaf8d906020015b60405180910390a150565b60026000541415610f835760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b600260005533610f91611f55565b600855610f9c611364565b600d55610fa7611613565b6007556001600160a01b0381161561102257610fc281610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055610ff68161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b610d52826129b4565b6012818154811061103b57600080fd5b600091825260209091200154905081565b6001600160a01b0381166000908152600f6020908152604080832054600e909252822054610888919061088290670de0b6b3a76400009061087c9061085d90610857611364565b600260005414156110e65760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055336110f4611f55565b6008556110ff611364565b600d5561110a611613565b6007556001600160a01b038116156111855761112581610810565b6001600160a01b0382166000908152600a60209081526040808320939093556008546009909152919020556111598161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b336000908152600a60205260409020548015610d5257336000818152600a60205260408120556002546111c4916001600160a01b039091169083612866565b60405181815233907fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048690602001610d49565b6111fe612af9565b565b6001546001600160a01b031633146112485760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b03821660009081526010602052604090205460115461126d9161282f565b60119081556001600160a01b038316600090815260106020526040902082905554611298908261285a565b6011555050565b6001546001600160a01b031633146112e75760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b039091166000908152600f6020526040902055565b600260005414156113565760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055610d54816129b4565b6000601654600014156113785750600d5490565b610bd46113a760165461087c670de0b6b3a76400006113a1600c546113a1600754610857611613565b90612842565b600d549061285a565b600260005414156114035760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b60026000908155338152601060205260409020548015610d5457336000908152601060205260409020546011546114399161282f565b60115533600081815260106020526040812055600254611465916001600160a01b039091169083612866565b60405181815233907fef4696bdcf47e292773442e4169d670e1b2d0d3f5ceff2a5c1e236c10109ee809060200160405180910390a2506001600055565b6001546001600160a01b031633146114ea5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6111fe6000612b86565b6001546001600160a01b0316331461153c5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6115468282612be5565b5050565b6001546001600160a01b031633146115925760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6115bb6115a76001546001600160a01b031690565b6002546001600160a01b0316903086612cb7565b600b546001600160a01b0316158015906115d55750600082115b15611603576116036115ef6001546001600160a01b031690565b600b546001600160a01b0316903085612cb7565b61160e838383612d0e565b505050565b6000610bd4426004546130b9565b6111fe61290f565b6001546001600160a01b031633146116715760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6003546001600160a01b03838116911614156116f55760405162461bcd60e51b815260206004820152602160248201527f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560448201527f6e0000000000000000000000000000000000000000000000000000000000000060648201526084016108d2565b61171b61170a6001546001600160a01b031690565b6001600160a01b0384169083612866565b604080516001600160a01b0384168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa289101610b8b565b6001546001600160a01b031633146116035760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6013818154811061103b57600080fd5b6001546001600160a01b031633146117fa5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146118715760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576118b9838281518110611892576118926136c9565b60200260200101518383815181106118ac576118ac6136c9565b6020026020010151611200565b6118c2816136f5565b9050611874565b6001546001600160a01b031633146119115760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146119885760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576119d08382815181106119a9576119a96136c9565b60200260200101518383815181106119c3576119c36136c9565b60200260200101516120ce565b6119d9816136f5565b905061198b565b6001546001600160a01b03163314611a285760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6002546001600160a01b0382811691161415611aac5760405162461bcd60e51b815260206004820152603960248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d207468652072657761726420746f6b656e0000000000000060648201526084016108d2565b6003546001600160a01b0382811691161415611b305760405162461bcd60e51b815260206004820152603a60248201527f54686520626f6f7374657220746f6b656e206d7573742062652064696666657260448201527f656e742066726f6d20746865207374616b696e6720746f6b656e00000000000060648201526084016108d2565b600b805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081179091556040519081527f0c6fec5b80219c372da56cb4d1ef3e172069953fa5c72ececf0d0dfe1109260b90602001610f25565b6000805b601254811015611c305760128181548110611bac57611bac6136c9565b60009182526020808320909101546001600160a01b03871683526014909152604090912054611bdc90429061282f565b1015611c2057611c186103e861087c60138481548110611bfe57611bfe6136c9565b90600052602060002001548661284290919063ffffffff16565b915050610888565b611c29816136f5565b9050611b8f565b5060009392505050565b60026000541415611c8d5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff1615611cdf5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b33611ce8611f55565b600855611cf3611364565b600d55611cfe611613565b6007556001600160a01b03811615611d7957611d1981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055611d4d8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b60008211611dc95760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b601654611dd6908361285a565b60165533600090815260176020526040902054611df3908361285a565b33600081815260176020526040902091909155600354611e20916001600160a01b03909116903085612cb7565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d90610d499085815260200190565b6001546001600160a01b03163314611eac5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6004544211611f495760405162461bcd60e51b815260206004820152605860248201527f50726576696f7573207265776172647320706572696f64206d7573742062652060448201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260648201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000608482015260a4016108d2565b611f52816130cf565b50565b600060165460001415611f69575060085490565b610bd4611f9260165461087c670de0b6b3a76400006113a16005546113a1600754610857611613565b6008549061285a565b6001546001600160a01b03163314611fe35760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b61200e611ff86001546001600160a01b031690565b6015546003546001600160a01b03169190612866565b7f6857c770f3cb43e9c19050a37dd914ec876241c1f4b487d26a1d4f5d3054f49b60155460405161204191815260200190565b60405180910390a16000601555565b6001546001600160a01b031633146120985760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b600755565b336000908152601760205260409020546120b690610f30565b6120be611093565b6120c6610bd9565b6111fe6113b0565b6001546001600160a01b031633146121165760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b039091166000908152600a6020526040902055565b600260005414156121855760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108d2565b6002600055600154600160a01b900460ff16156121d75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b336121e0611f55565b6008556121eb611364565b600d556121f6611613565b6007556001600160a01b038116156122715761221181610810565b6001600160a01b0382166000908152600a60209081526040808320939093556008546009909152919020556122458161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b600086116122c15760405162461bcd60e51b815260206004820152600e60248201527f43616e6e6f74207374616b65203000000000000000000000000000000000000060448201526064016108d2565b6016546122ce908761285a565b601655336000908152601760205260409020546122eb908761285a565b33600081815260176020526040908190209290925560035491517fd505accf0000000000000000000000000000000000000000000000000000000081526004810191909152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c481018490526001600160a01b039091169063d505accf9060e401600060405180830381600087803b15801561238a57600080fd5b505af115801561239e573d6000803e3d6000fd5b50506003546123bb92506001600160a01b03169050333089612cb7565b3360008181526014602052604090819020429055517f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906123ff9089815260200190565b60405180910390a25050600160005550505050565b6001546001600160a01b0316331461245c5760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b6001600160a01b0381166124d85760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f646472657373000000000000000000000000000000000000000000000000000060648201526084016108d2565b611f5281612b86565b6000610bd4600654600c5461284290919063ffffffff16565b6001546001600160a01b031633146125425760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b80518251146125b95760405162461bcd60e51b815260206004820152603960248201527f5468652073616d65206e756d626572206f662061646472657373657320616e6460448201527f20616d6f756e7473206d7573742062652070726f76696465640000000000000060648201526084016108d2565b60005b825181101561160e576126018382815181106125da576125da6136c9565b60200260200101518383815181106125f4576125f46136c9565b602002602001015161129f565b61260a816136f5565b90506125bc565b6001546001600160a01b031633146126595760405162461bcd60e51b8152602060048201819052602482015260008051602061388783398151915260448201526064016108d2565b600b546001600160a01b03166126fd5760405162461bcd60e51b815260206004820152604160248201527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520776173206e6f20626f6f7374657220746f6b656e20736560648201527f7400000000000000000000000000000000000000000000000000000000000000608482015260a4016108d2565b60165415612775576040805162461bcd60e51b81526020600482015260248101919091527f43616e6e6f74207265636f766572206c6566746f76657220626f6f737465722060448201527f696620746865726520617265207374696c6c207374616b656420746f6b656e7360648201526084016108d2565b600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa1580156127be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e291906136b0565b905080156127ff576127ff610b446001546001600160a01b031690565b6040518181527fa075ee3dcd38efb87f0f97160a935b6a43768378263338beea06b9681f66151d90602001610f25565b600061283b8284613710565b9392505050565b600061283b8284613727565b600061283b8284613746565b600061283b8284613768565b6040516001600160a01b03831660248201526044810182905261160e9084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152613104565b600154600160a01b900460ff161561295c5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016108d2565b6001805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586129973390565b6040516001600160a01b03909116815260200160405180910390a1565b60008111612a045760405162461bcd60e51b815260206004820152601160248201527f43616e6e6f74207769746864726177203000000000000000000000000000000060448201526064016108d2565b601654612a11908261282f565b6016556000612a203383611b8b565b33600090815260176020526040902054909150612a3d908361282f565b33600090815260176020526040812091909155612a5a838361282f565b600354909150612a74906001600160a01b03163383612866565b60405181815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d59060200160405180910390a2811561160e5760405182815233907f9dc46f23cfb5ddcad0ae7ea2be38d47fec07bb9382ec7e564efc69e036dd66ce9060200160405180910390a2601554612af1908361285a565b601555505050565b600154600160a01b900460ff16612b525760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016108d2565b6001805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa33612997565b600180546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b8051825114612c5e576040805162461bcd60e51b81526020600482015260248101919091527f466565207363686564756c6520616e64207769746864726177616c206665657360448201527f20617272617973206d757374206265207468652073616d65206c656e6774682160648201526084016108d2565b8151612c71906012906020850190613378565b508051612c85906013906020840190613378565b507fe5a2c1e4acf2a2da539a1183c56fbbcec4b66dbc828b76f1c1bf365f1887886b8282604051610b8b9291906137bb565b6040516001600160a01b0380851660248301528316604482015260648101829052612d089085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016128ab565b50505050565b6000612d18611f55565b600855612d23611364565b600d55612d2e611613565b6007556001600160a01b03811615612da957612d4981610810565b6001600160a01b0382166000908152600a6020908152604080832093909355600854600990915291902055612d7d8161104c565b6001600160a01b0382166000908152600f6020908152604080832093909355600d54600e909152919020555b8115612db857612db8826130cf565b6004544210612de857600654612dcf90859061284e565b600555600654612de090849061284e565b600c55612e54565b600454600090612df8904261282f565b90506000612e116005548361284290919063ffffffff16565b600654909150612e259061087c888461285a565b600555600c54600090612e39908490612842565b600654909150612e4d9061087c888461285a565b600c555050505b6002546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612e9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec191906136b0565b9050612ed86006548261284e90919063ffffffff16565b600554111580612f1f57506003546002546001600160a01b039081169116148015612f1f5750612f196016546108576006548461284e90919063ffffffff16565b60055411155b612f6b5760405162461bcd60e51b815260206004820152601860248201527f50726f76696465642072657761726420746f6f2068696768000000000000000060448201526064016108d2565b600b546001600160a01b03161561305357600b546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015612fc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fe991906136b0565b90506130006006548261284e90919063ffffffff16565b600c5411156130515760405162461bcd60e51b815260206004820181905260248201527f50726f766964656420626f6f737465722072657761726420746f6f206869676860448201526064016108d2565b505b426007819055600654613066919061285a565b600455613071612af9565b60408051868152602081018690529081018490527f748824204e79acdab8f1a9977cbc584250e206ad90d05ef198799f9d6ee93a7d9060600160405180910390a15050505050565b60008183106130c8578161283b565b5090919050565b60068190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610f25565b6000613159826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131e99092919063ffffffff16565b80519091501561160e578080602001905181019061317791906137e9565b61160e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016108d2565b60606131f88484600085613200565b949350505050565b6060824710156132785760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c000000000000000000000000000000000000000000000000000060648201526084016108d2565b843b6132c65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016108d2565b600080866001600160a01b031685876040516132e29190613837565b60006040518083038185875af1925050503d806000811461331f576040519150601f19603f3d011682016040523d82523d6000602084013e613324565b606091505b509150915061333482828661333f565b979650505050505050565b6060831561334e57508161283b565b82511561335e5782518084602001fd5b8160405162461bcd60e51b81526004016108d29190613853565b8280548282559060005260206000209081019282156133b3579160200282015b828111156133b3578251825591602001919060010190613398565b506133bf9291506133c3565b5090565b5b808211156133bf57600081556001016133c4565b80356001600160a01b03811681146133ef57600080fd5b919050565b60006020828403121561340657600080fd5b61283b826133d8565b60006020828403121561342157600080fd5b5035919050565b6000806040838503121561343b57600080fd5b613444836133d8565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff8111828210171561349157613491613452565b604052919050565b600067ffffffffffffffff8211156134b3576134b3613452565b5060051b60200190565b600082601f8301126134ce57600080fd5b813560206134e36134de83613499565b613468565b82815260059290921b8401810191818101908684111561350257600080fd5b8286015b8481101561351d5780358352918301918301613506565b509695505050505050565b6000806040838503121561353b57600080fd5b823567ffffffffffffffff8082111561355357600080fd5b61355f868387016134bd565b9350602085013591508082111561357557600080fd5b50613582858286016134bd565b9150509250929050565b6000806000606084860312156135a157600080fd5b505081359360208301359350604090920135919050565b600080604083850312156135cb57600080fd5b823567ffffffffffffffff808211156135e357600080fd5b818501915085601f8301126135f757600080fd5b813560206136076134de83613499565b82815260059290921b8401810191818101908984111561362657600080fd5b948201945b8386101561364b5761363c866133d8565b8252948201949082019061362b565b9650508601359250508082111561357557600080fd5b600080600080600060a0868803121561367957600080fd5b8535945060208601359350604086013560ff8116811461369857600080fd5b94979396509394606081013594506080013592915050565b6000602082840312156136c257600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613709576137096136df565b5060010190565b600082821015613722576137226136df565b500390565b6000816000190483118215151615613741576137416136df565b500290565b60008261376357634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561377b5761377b6136df565b500190565b600081518084526020808501945080840160005b838110156137b057815187529582019590820190600101613794565b509495945050505050565b6040815260006137ce6040830185613780565b82810360208401526137e08185613780565b95945050505050565b6000602082840312156137fb57600080fd5b8151801515811461283b57600080fd5b60005b8381101561382657818101518382015260200161380e565b83811115612d085750506000910152565b6000825161384981846020870161380b565b9190910192915050565b602081526000825180602084015261387281604085016020870161380b565b601f01601f1916919091016040019291505056fe4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572a2646970667358221220362c2bfa3419b92432acb1e48c03aab4e6617c26e4c399ff72ecafc77942c73364736f6c634300080a0033