Contract Address Details

0x5C78a8dEAd748Ccfa3D1e70E72854D0CaB2eeAd0

Contract Name
Rewarder
Creator
0x2b0b98–758b1b at 0x16ebdf–b57ce6
Balance
0 CRO ( )
Tokens
Fetching tokens...
Transactions
1 Transactions
Transfers
23,347 Transfers
Gas Used
119,474
Last Balance Update
13222222
Contract name:
Rewarder




Optimization enabled
true
Compiler version
v0.6.12+commit.27d51765




Optimization runs
200
EVM Version
default




Verified at
2022-02-18T01:44:02.593440Z

Constructor Arguments

000000000000000000000000dd73dea10abc2bff99c60882ec5b2b81bb1dc5b2000000000000000000000000000000000000000000000a604b9a42df9ca0000000000000000000000000000000000000000000000000000000000000620f5200000000000000000000000000000000000000000000000000000000006285f900000000000000000000000000dccd6455ae04b03d785f12196b492b18129564bc000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e76

Arg [0] (address) : 0xdd73dea10abc2bff99c60882ec5b2b81bb1dc5b2
Arg [1] (uint256) : 49000000000000000000000
Arg [2] (uint256) : 1645171200
Arg [3] (uint256) : 1652947200
Arg [4] (address) : 0xdccd6455ae04b03d785f12196b492b18129564bc
Arg [5] (address) : 0xbc149c62efe8afc61728fc58b1b66a0661712e76

              

Contract source code

// Sources flattened with hardhat v2.6.7 https://hardhat.org

// File @openzeppelin/contracts/utils/[email protected]

// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File @openzeppelin/contracts/access/[email protected]

pragma solidity >=0.6.0 <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() internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), 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 {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

// File @openzeppelin/contracts/math/[email protected]

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library 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) {
        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) {
        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) {
        // 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) {
        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) {
        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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        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) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b > 0, "SafeMath: division by zero");
        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) {
        require(b > 0, "SafeMath: modulo by zero");
        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) {
        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.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        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) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

// File @openzeppelin/contracts/token/ERC20/[email protected]

pragma solidity >=0.6.0 <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.6.2 <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;
        // solhint-disable-next-line no-inline-assembly
        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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// File @openzeppelin/contracts/token/ERC20/[email protected]

pragma solidity >=0.6.0 <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 SafeMath for uint256;
    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'
        // solhint-disable-next-line max-line-length
        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).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(
            value,
            "SafeERC20: decreased allowance below zero"
        );
        _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
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// File contracts/ICraftsman.sol

pragma solidity 0.6.12;

/**
 * @title ICraftsman
 * @notice It is an interface for Craftsman.sol
 */
interface ICraftsman {
    /**
     * @notice deposit LP tokens for VVS allocation.
     * @param _pid poolId
     * @param _amount amount of LP token to deposit
     */
    function deposit(uint256 _pid, uint256 _amount) external;

    /**
     * @notice withdraw LP tokens
     * @param _pid poolId
     * @param _amount amount of LP token to deposit
     */
    function withdraw(uint256 _pid, uint256 _amount) external;

    /**
     * @notice withdraw without caring about rewards. EMERGENCY ONLY.
     * @param _pid poolId
     */
    function emergencyWithdraw(uint256 _pid) external;

    /**
     * @notice view function to check user pending vvs
     * @param _pid poolId
     * @param _user address of user
     */
    function pendingVVS(uint256 _pid, address _user) external view returns (uint256);

    /**
     * @notice view function to check user's deposited LP and rewardDebt
     * @param _pid poolId
     * @param _user address of user
     */
    function userInfo(uint256 _pid, address _user) external view returns (uint256 amount, uint256 rewardDebt);

    /**
     * @notice view function to check pool info
     * @param _pid poolId
     */
    function poolInfo(uint256 _pid)
        external
        view
        returns (
            address lpToken,
            uint256 allocPoint,
            uint256 lastRewardBlock,
            uint256 accVVSPerShare
        );

    /**
     * @notice view function to check vvs token address registered in craftsman
     */
    function vvs() external view returns (address);
}

// File contracts/Rewarder.sol

pragma solidity 0.6.12;

contract Rewarder is Ownable {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    struct UserInfo {
        uint256 rewardDebt; // Reward debt - amount of reward token paid out to user
    }

    struct PoolInfo {
        uint256 allocPoint;
        uint256 lastRewardTime;
        uint256 accRewardPerShare; // Accumulated reward tokens per share, times ACC_TOKEN_PRECISION. See below.
    }

    IERC20 public immutable rewardToken;

    mapping(uint256 => PoolInfo) public poolInfo;

    uint256[] public poolIds;

    /// @notice Info of each user that stakes LP tokens.
    mapping(uint256 => mapping(address => UserInfo)) public userInfo;
    /// @dev Total allocation points. Must be the sum of all allocation points in all pools.
    uint256 public totalAllocPoint;

    uint256 public rewardPerSecond; // number of token per sec
    uint256 public rewardStartTimestamp; // timestamp when reward emission starts
    uint256 public rewardEndTimestamp; // timestamp when reward emission ends
    uint256 private constant ACC_TOKEN_PRECISION = 1e12;

    ICraftsman public immutable craftsman;
    ICraftsman public immutable craftsmanV2;

    /// @dev pending represent how much rewardToken user received
    event OnVVSReward(uint256 indexed pid, address indexed user, uint256 amount, uint256 pending);
    event AddPool(uint256 indexed pid, uint256 allocPoint);
    event SetPool(uint256 indexed pid, uint256 allocPoint);
    event SetRewardPerSecond(uint256 rewardPerSecond);
    event SetRewardStartTimestamp(uint256 rewardStartTimestamp);
    event SetRewardEndTimestamp(uint256 rewardEndTimestamp);
    event EmergencyRewardWithdraw(address indexed user, uint256 amount);

    modifier onlyCraftsmanV2() {
        require(msg.sender == address(craftsmanV2), "Only CraftsmanV2 can call this function.");
        _;
    }

    constructor(
        IERC20 _rewardToken,
        uint256 _rewardPerSecond,
        uint256 _rewardStartTimestamp,
        uint256 _rewardEndTimestamp,
        ICraftsman _craftsman,
        ICraftsman _craftsmanV2
    ) public {
        rewardToken = _rewardToken;
        rewardPerSecond = _rewardPerSecond;
        rewardStartTimestamp = _rewardStartTimestamp;
        rewardEndTimestamp = _rewardEndTimestamp;
        craftsman = _craftsman;
        craftsmanV2 = _craftsmanV2;
    }

    /// @notice send any pending rewardToken to user
    /// @dev MUST call this function before update user.amount at craftsmanV2. If contract has not enough
    ///         reward token, this function will throw an error.
    /// @param _pid pid to check for reward
    /// @param _user address of user
    /// @param _currentAmount current amount of the user after deposit | withdraw
    function onVVSReward(
        uint256 _pid,
        address _user,
        uint256 _currentAmount
    ) external onlyCraftsmanV2 {
        updatePool(_pid);

        PoolInfo storage pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        (uint256 userAmount, ) = craftsmanV2.userInfo(_pid, _user);

        uint256 pending;
        if (userAmount > 0) {
            pending = (userAmount.mul(pool.accRewardPerShare).div(ACC_TOKEN_PRECISION)).sub(user.rewardDebt);
            rewardToken.safeTransfer(_user, pending);
        }

        user.rewardDebt = _currentAmount.mul(pool.accRewardPerShare).div(ACC_TOKEN_PRECISION);
        emit OnVVSReward(_pid, _user, _currentAmount, pending);
    }

    /*
     * @notice withdraw excess token.
     * @dev Only callable by owner. Needs to be for emergency.
     */
    function emergencyRewardWithdraw(uint256 _amount) external onlyOwner {
        require(block.timestamp > rewardEndTimestamp, "Reward not ended");
        rewardToken.safeTransfer(address(msg.sender), _amount);
        emit EmergencyRewardWithdraw(msg.sender, _amount);
    }

    /// @notice Sets the reward per second to be distributed. Can only be called by the owner.
    /// @param _rewardPerSecond The amount of reward token to be distributed per second.
    function setRewardPerSecond(uint256 _rewardPerSecond) public onlyOwner {
        massUpdatePools();

        rewardPerSecond = _rewardPerSecond;
        emit SetRewardPerSecond(_rewardPerSecond);
    }

    /// @notice Returns the number of pools.
    function poolLength() public view returns (uint256 pools) {
        pools = poolIds.length;
    }

    /// @notice Add a new LP to the pool. Can only be called by the owner.
    /// @param _allocPoint AP of the new pool.
    /// @param _pid Pid on CraftsmanV2
    function add(
        uint256 _allocPoint,
        uint256 _pid,
        bool _withUpdate
    ) public onlyOwner {
        require(poolInfo[_pid].lastRewardTime == 0, "Pool already exists");

        if (_withUpdate) {
            massUpdatePools();
        }

        uint256 lastRewardTime = block.timestamp > rewardStartTimestamp ? block.timestamp : rewardStartTimestamp;
        totalAllocPoint = totalAllocPoint.add(_allocPoint);

        poolInfo[_pid] = PoolInfo({allocPoint: _allocPoint, lastRewardTime: lastRewardTime, accRewardPerShare: 0});
        poolIds.push(_pid);

        emit AddPool(_pid, _allocPoint);
    }

    /// @notice Update the given pool's reward allocation point. Can only be called by the owner.
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _allocPoint New AP of the pool.
    /// @param _withUpdate Update the pool.accRewardPerShare before alloc point adjustment
    function set(
        uint256 _pid,
        uint256 _allocPoint,
        bool _withUpdate
    ) public onlyOwner {
        if (_withUpdate) {
            massUpdatePools();
        }

        totalAllocPoint = totalAllocPoint.sub(poolInfo[_pid].allocPoint).add(_allocPoint);
        poolInfo[_pid].allocPoint = _allocPoint;
        emit SetPool(_pid, _allocPoint);
    }

    /// @notice View function to see pending Token
    /// @param _pid The index of the pool. See `poolInfo`.
    /// @param _user Address of user.
    /// @return pending reward for a given user.
    function pendingToken(uint256 _pid, address _user) public view returns (address, uint256) {
        PoolInfo memory pool = poolInfo[_pid];
        UserInfo storage user = userInfo[_pid][_user];
        uint256 accRewardPerShare = pool.accRewardPerShare;
        (uint256 lpSupply, ) = craftsman.userInfo(_pid, address(craftsmanV2));
        if (block.timestamp > pool.lastRewardTime && lpSupply != 0) {
            uint256 multiplier = _getMultiplier(pool.lastRewardTime, block.timestamp);
            uint256 reward = multiplier.mul(rewardPerSecond).mul(pool.allocPoint).div(totalAllocPoint);

            accRewardPerShare = accRewardPerShare.add(reward.mul(ACC_TOKEN_PRECISION).div(lpSupply));
        }

        (uint256 userAmount, ) = craftsmanV2.userInfo(_pid, _user);
        uint256 pending = userAmount.mul(accRewardPerShare).div(ACC_TOKEN_PRECISION).sub(user.rewardDebt);

        return (address(rewardToken), pending);
    }

    function setRewardStartTimestamp(uint256 _rewardStartTimestamp) public onlyOwner {
        require(block.timestamp < rewardStartTimestamp, "Reward has started");
        require(block.timestamp < _rewardStartTimestamp, "New start time must be after current timestamp");
        require(rewardEndTimestamp > _rewardStartTimestamp, "New start time must be before end timestamp");

        rewardStartTimestamp = _rewardStartTimestamp;

        massUpdatePools();
        emit SetRewardStartTimestamp(_rewardStartTimestamp);
    }

    function setRewardEndTimestamp(uint256 _rewardEndTimestamp) public onlyOwner {
        require(_rewardEndTimestamp > rewardStartTimestamp, "New end time must be after start timestamp");

        rewardEndTimestamp = _rewardEndTimestamp;

        massUpdatePools();
        emit SetRewardEndTimestamp(_rewardEndTimestamp);
    }

    /// Update reward variables for all pools. Be careful of gas spending!
    function massUpdatePools() public {
        uint256 length = poolIds.length;
        for (uint256 i = 0; i < length; ++i) {
            updatePool(poolIds[i]);
        }
    }

    /// @notice Update reward variables of the given pool.
    /// @param _pid The index of the pool
    function updatePool(uint256 _pid) public {
        PoolInfo storage pool = poolInfo[_pid];
        if (block.timestamp <= pool.lastRewardTime) {
            return;
        }

        (uint256 lpSupply, ) = craftsman.userInfo(_pid, address(craftsmanV2));
        if (lpSupply == 0) {
            pool.lastRewardTime = block.timestamp;
            return;
        }

        uint256 multiplier = _getMultiplier(pool.lastRewardTime, block.timestamp);
        uint256 reward = multiplier.mul(rewardPerSecond).mul(pool.allocPoint).div(totalAllocPoint);
        pool.accRewardPerShare = pool.accRewardPerShare.add((reward.mul(ACC_TOKEN_PRECISION) / lpSupply));
        pool.lastRewardTime = block.timestamp;
    }

    /// @dev get the number of seconds passed since the last reward
    /// @param _lastRewardTime pool.lastRewardTime
    /// @param _currentTimestamp - block.timestamp
    function _getMultiplier(uint256 _lastRewardTime, uint256 _currentTimestamp) internal view returns (uint256) {
        // Scenario 1: Not started yet
        if (block.timestamp < rewardStartTimestamp) {
            return 0;
        }

        // Scenario 2: Reward started and not ended. (on-going)
        if (_currentTimestamp <= rewardEndTimestamp) {
            return _currentTimestamp.sub(_lastRewardTime);
        }

        // Scenario 3: pool's last reward already over rewardEndTimestamp
        if (_lastRewardTime >= rewardEndTimestamp) {
            return 0;
        }

        // Scenario 4: reward ended, calculate the diff from last claim
        return rewardEndTimestamp.sub(_lastRewardTime);
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_rewardToken","internalType":"contract IERC20"},{"type":"uint256","name":"_rewardPerSecond","internalType":"uint256"},{"type":"uint256","name":"_rewardStartTimestamp","internalType":"uint256"},{"type":"uint256","name":"_rewardEndTimestamp","internalType":"uint256"},{"type":"address","name":"_craftsman","internalType":"contract ICraftsman"},{"type":"address","name":"_craftsmanV2","internalType":"contract ICraftsman"}]},{"type":"event","name":"AddPool","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"allocPoint","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EmergencyRewardWithdraw","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OnVVSReward","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"pending","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":"SetPool","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"allocPoint","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetRewardEndTimestamp","inputs":[{"type":"uint256","name":"rewardEndTimestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetRewardPerSecond","inputs":[{"type":"uint256","name":"rewardPerSecond","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetRewardStartTimestamp","inputs":[{"type":"uint256","name":"rewardStartTimestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"add","inputs":[{"type":"uint256","name":"_allocPoint","internalType":"uint256"},{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"bool","name":"_withUpdate","internalType":"bool"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ICraftsman"}],"name":"craftsman","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ICraftsman"}],"name":"craftsmanV2","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyRewardWithdraw","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"massUpdatePools","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"onVVSReward","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"address","name":"_user","internalType":"address"},{"type":"uint256","name":"_currentAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"pendingToken","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"poolIds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"allocPoint","internalType":"uint256"},{"type":"uint256","name":"lastRewardTime","internalType":"uint256"},{"type":"uint256","name":"accRewardPerShare","internalType":"uint256"}],"name":"poolInfo","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"pools","internalType":"uint256"}],"name":"poolLength","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardEndTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerSecond","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardStartTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"rewardToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"set","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_allocPoint","internalType":"uint256"},{"type":"bool","name":"_withUpdate","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardEndTimestamp","inputs":[{"type":"uint256","name":"_rewardEndTimestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardPerSecond","inputs":[{"type":"uint256","name":"_rewardPerSecond","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardStartTimestamp","inputs":[{"type":"uint256","name":"_rewardStartTimestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalAllocPoint","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePool","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"rewardDebt","internalType":"uint256"}],"name":"userInfo","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101585760003560e01c8063715018a6116100c357806393f1a40b1161007c57806393f1a40b14610370578063f2fde38b1461039c578063f577988e146103c2578063f7c618c1146103df578063f861306e146103e7578063fcb685bc146103ef57610158565b8063715018a614610301578063823c27ff146103095780638b183040146103265780638bc1d8c0146103585780638da5cb5b146103605780638f10369a1461036857610158565b806348e43af41161011557806348e43af41461022857806351eb05a614610277578063630b5ba11461029457806364482f791461029c57806366da5815146102c757806369883b4e146102e457610158565b806307f6a6c21461015d578063081e3eda1461018a5780631526fe27146101a457806317caf6f1146101df57806327c2bca8146101e75780633279beab1461020b575b600080fd5b6101886004803603606081101561017357600080fd5b508035906020810135906040013515156103f7565b005b61019261058d565b60408051918252519081900360200190f35b6101c1600480360360208110156101ba57600080fd5b5035610593565b60408051938452602084019290925282820152519081900360600190f35b6101926105b3565b6101ef6105b9565b604080516001600160a01b039092168252519081900360200190f35b6101886004803603602081101561022157600080fd5b50356105dd565b6102546004803603604081101561023e57600080fd5b50803590602001356001600160a01b03166106f5565b604080516001600160a01b03909316835260208301919091528051918290030190f35b6101886004803603602081101561028d57600080fd5b503561097d565b610188610aea565b610188600480360360608110156102b257600080fd5b50803590602081013590604001351515610b24565b610188600480360360208110156102dd57600080fd5b5035610c0a565b610192600480360360208110156102fa57600080fd5b5035610caf565b610188610ccd565b6101886004803603602081101561031f57600080fd5b5035610d79565b6101886004803603606081101561033c57600080fd5b508035906001600160a01b036020820135169060400135610ee7565b6101926110f5565b6101ef6110fb565b61019261110a565b6101926004803603604081101561038657600080fd5b50803590602001356001600160a01b0316611110565b610188600480360360208110156103b257600080fd5b50356001600160a01b031661112d565b610188600480360360208110156103d857600080fd5b503561122f565b6101ef611313565b6101ef611337565b61019261135b565b6103ff611361565b6001600160a01b03166104106110fb565b6001600160a01b031614610459576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b60008281526001602081905260409091200154156104b4576040805162461bcd60e51b8152602060048201526013602482015272506f6f6c20616c72656164792065786973747360681b604482015290519081900360640190fd5b80156104c2576104c2610aea565b600060065442116104d5576006546104d7565b425b6004549091506104e79085611365565b60045560408051606081018252858152602080820184815260008385018181528882526001808552868320955186559251858401555160029485015583549182018455929092527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9091018590558151868152915185927fa6b36ea399c1eae2ba98a011138f78722b48f46ad93349269348ccc6e8f1cced92908290030190a250505050565b60025490565b600160208190526000918252604090912080549181015460029091015483565b60045481565b7f000000000000000000000000dccd6455ae04b03d785f12196b492b18129564bc81565b6105e5611361565b6001600160a01b03166105f66110fb565b6001600160a01b03161461063f576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b6007544211610688576040805162461bcd60e51b815260206004820152601060248201526f14995dd85c99081b9bdd08195b99195960821b604482015290519081900360640190fd5b6106bc6001600160a01b037f000000000000000000000000dd73dea10abc2bff99c60882ec5b2b81bb1dc5b21633836113c8565b60408051828152905133917f2d4434bb59801e733e9ce3df40b0c5518861a5fcdeec1906e83e03c755872b42919081900360200190a250565b600080610700611858565b506000848152600160208181526040808420815160608101835281548152938101548484015260020154838201908152888552600383528185206001600160a01b03808a1687529352818520905182516393f1a40b60e01b8152600481018b90527f000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e7685166024820152835195969295919492937f000000000000000000000000dccd6455ae04b03d785f12196b492b18129564bc909316926393f1a40b92604480840193829003018186803b1580156107d857600080fd5b505afa1580156107ec573d6000803e3d6000fd5b505050506040513d604081101561080257600080fd5b505160208501519091504211801561081957508015155b1561088557600061082e85602001514261141f565b9050600061086160045461085b88600001516108556005548761146b90919063ffffffff16565b9061146b565b906114c4565b90506108806108798461085b8464e8d4a5100061146b565b8590611365565b935050505b60007f000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e766001600160a01b03166393f1a40b8a8a6040518363ffffffff1660e01b815260040180838152602001826001600160a01b0316815260200192505050604080518083038186803b1580156108fb57600080fd5b505afa15801561090f573d6000803e3d6000fd5b505050506040513d604081101561092557600080fd5b5051845490915060009061094c9061094664e8d4a5100061085b868961146b565b9061152b565b7f000000000000000000000000dd73dea10abc2bff99c60882ec5b2b81bb1dc5b29b909a5098505050505050505050565b600081815260016020819052604090912090810154421161099e5750610ae7565b60007f000000000000000000000000dccd6455ae04b03d785f12196b492b18129564bc6001600160a01b03166393f1a40b847f000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e766040518363ffffffff1660e01b815260040180838152602001826001600160a01b0316815260200192505050604080518083038186803b158015610a3457600080fd5b505afa158015610a48573d6000803e3d6000fd5b505050506040513d6040811015610a5e57600080fd5b5051905080610a74575042600190910155610ae7565b6000610a8483600101544261141f565b90506000610aab60045461085b86600001546108556005548761146b90919063ffffffff16565b9050610ad483610ac08364e8d4a5100061146b565b81610ac757fe5b6002870154919004611365565b6002850155505042600190920191909155505b50565b60025460005b81811015610b2057610b1860028281548110610b0857fe5b906000526020600020015461097d565b600101610af0565b5050565b610b2c611361565b6001600160a01b0316610b3d6110fb565b6001600160a01b031614610b86576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b8015610b9457610b94610aea565b600083815260016020526040902054600454610bbb918491610bb59161152b565b90611365565b6004556000838152600160209081526040918290208490558151848152915185927fc0cfd54d2de2b55f1e6e108d3ec53ff0a1abe6055401d32c61e9433b747ef9f892908290030190a2505050565b610c12611361565b6001600160a01b0316610c236110fb565b6001600160a01b031614610c6c576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b610c74610aea565b60058190556040805182815290517f9981f93efb1f00e191e4911e94be7586e0643ea2948cd594baa6c3fe23ae654d9181900360200190a150565b60028181548110610cbc57fe5b600091825260209091200154905081565b610cd5611361565b6001600160a01b0316610ce66110fb565b6001600160a01b031614610d2f576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b610d81611361565b6001600160a01b0316610d926110fb565b6001600160a01b031614610ddb576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b6006544210610e26576040805162461bcd60e51b815260206004820152601260248201527114995dd85c99081a185cc81cdd185c9d195960721b604482015290519081900360640190fd5b804210610e645760405162461bcd60e51b815260040180806020018281038252602e8152602001806119ae602e913960400191505060405180910390fd5b8060075411610ea45760405162461bcd60e51b815260040180806020018281038252602b81526020018061192f602b913960400191505060405180910390fd5b6006819055610eb1610aea565b6040805182815290517f333fbfe183fcd0d2b5c40ad00a9aea8f2ef8d7187c5e0d7c76f40b060286b87c9181900360200190a150565b336001600160a01b037f000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e761614610f4e5760405162461bcd60e51b81526004018080602001828103825260288152602001806119076028913960400191505060405180910390fd5b610f578361097d565b6000838152600160209081526040808320600383528184206001600160a01b038088168087529190945282852083516393f1a40b60e01b8152600481018a9052602481019290925283519295909490937f000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e76909116926393f1a40b926044808201939291829003018186803b158015610fee57600080fd5b505afa158015611002573d6000803e3d6000fd5b505050506040513d604081101561101857600080fd5b50519050600081156110825761104c836000015461094664e8d4a5100061085b88600201548761146b90919063ffffffff16565b90506110826001600160a01b037f000000000000000000000000dd73dea10abc2bff99c60882ec5b2b81bb1dc5b21687836113c8565b6110a264e8d4a5100061085b86600201548861146b90919063ffffffff16565b8355604080518681526020810183905281516001600160a01b038916928a927fa5d23287037261ad22a2e3d11de58347493136c30d30cb40e1d1f746b69962b5929081900390910190a350505050505050565b60075481565b6000546001600160a01b031690565b60055481565b600360209081526000928352604080842090915290825290205481565b611135611361565b6001600160a01b03166111466110fb565b6001600160a01b03161461118f576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b6001600160a01b0381166111d45760405162461bcd60e51b815260040180806020018281038252602681526020018061187a6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b611237611361565b6001600160a01b03166112486110fb565b6001600160a01b031614611291576040805162461bcd60e51b815260206004820181905260248201526000805160206118e7833981519152604482015290519081900360640190fd5b60065481116112d15760405162461bcd60e51b815260040180806020018281038252602a815260200180611984602a913960400191505060405180910390fd5b60078190556112de610aea565b6040805182815290517ec120dc5e082694674c24ab7b88010f8ec91c9cfa404fc7b0418d5d267468ec9181900360200190a150565b7f000000000000000000000000dd73dea10abc2bff99c60882ec5b2b81bb1dc5b281565b7f000000000000000000000000bc149c62efe8afc61728fc58b1b66a0661712e7681565b60065481565b3390565b6000828201838110156113bf576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b90505b92915050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261141a908490611588565b505050565b6000600654421015611433575060006113c2565b600754821161144d57611446828461152b565b90506113c2565b600754831061145e575060006113c2565b6007546113bf908461152b565b60008261147a575060006113c2565b8282028284828161148757fe5b04146113bf5760405162461bcd60e51b81526004018080602001828103825260218152602001806118c66021913960400191505060405180910390fd5b600080821161151a576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161152357fe5b049392505050565b600082821115611582576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b60606115dd826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166116399092919063ffffffff16565b80519091501561141a578080602001905160208110156115fc57600080fd5b505161141a5760405162461bcd60e51b815260040180806020018281038252602a81526020018061195a602a913960400191505060405180910390fd5b60606116488484600085611652565b90505b9392505050565b6060824710156116935760405162461bcd60e51b81526004018080602001828103825260268152602001806118a06026913960400191505060405180910390fd5b61169c856117ae565b6116ed576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b60006060866001600160a01b031685876040518082805190602001908083835b6020831061172c5780518252601f19909201916020918201910161170d565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d806000811461178e576040519150601f19603f3d011682016040523d82523d6000602084013e611793565b606091505b50915091506117a38282866117b4565b979650505050505050565b3b151590565b606083156117c357508161164b565b8251156117d35782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b8381101561181d578181015183820152602001611805565b50505050905090810190601f16801561184a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040518060600160405280600081526020016000815260200160008152509056fe4f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373416464726573733a20696e73756666696369656e742062616c616e636520666f722063616c6c536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65724f6e6c79204372616674736d616e56322063616e2063616c6c20746869732066756e6374696f6e2e4e65772073746172742074696d65206d757374206265206265666f726520656e642074696d657374616d705361666545524332303a204552433230206f7065726174696f6e20646964206e6f7420737563636565644e657720656e642074696d65206d7573742062652061667465722073746172742074696d657374616d704e65772073746172742074696d65206d7573742062652061667465722063757272656e742074696d657374616d70a2646970667358221220cd76a1ee8c912404c8065e18042d8ba8799e548c4b0af4f2490ba3370febb1ff64736f6c634300060c0033