ETH Price: $2,938.89 (-0.31%)

Contract

0x02c3B99D986ef1612bAC63d4004fa79714D00012

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Set Reward Ratio165981952025-07-14 22:27:09194 days ago1752532029IN
0x02c3B99D...714D00012
0 ETH0.000000140.0010388
Set Reward Ratio162488392025-07-06 20:21:57202 days ago1751833317IN
0x02c3B99D...714D00012
0 ETH0.000000160.00146324
Set Reward Ratio158639552025-06-27 22:32:29211 days ago1751063549IN
0x02c3B99D...714D00012
0 ETH0.000000110.00100115
Claim Rewards158395592025-06-27 8:59:17212 days ago1751014757IN
0x02c3B99D...714D00012
0 ETH0.000000150.00150164
Stake158392752025-06-27 8:49:49212 days ago1751014189IN
0x02c3B99D...714D00012
0 ETH0.000000160.00150164
Set Reward Ratio153949002025-06-17 1:57:19222 days ago1750125439IN
0x02c3B99D...714D00012
0 ETH0.000000110.00100261
Set Reward Ratio139182382025-05-13 21:35:15256 days ago1747172115IN
0x02c3B99D...714D00012
0 ETH0.000000160.00100154
Set Reward Ratio138419242025-05-12 3:11:27258 days ago1747019487IN
0x02c3B99D...714D00012
0 ETH0.000000120.00100379
Set Reward Ratio137497892025-05-10 0:00:17260 days ago1746835217IN
0x02c3B99D...714D00012
0 ETH0.000000110.0010012
Set Reward Ratio137177422025-05-09 6:12:03261 days ago1746771123IN
0x02c3B99D...714D00012
0 ETH0.000000140.0011791
Set Reward Ratio137068342025-05-09 0:08:27261 days ago1746749307IN
0x02c3B99D...714D00012
0 ETH0.000000150.00102714
Withdraw Reward ...111685652025-03-11 5:59:29320 days ago1741672769IN
0x02c3B99D...714D00012
0 ETH0.000000130.00100029
Set Reward Ratio111673782025-03-11 5:19:55320 days ago1741670395IN
0x02c3B99D...714D00012
0 ETH0.000000190.00100031
Set Reward Ratio111138432025-03-09 23:35:25321 days ago1741563325IN
0x02c3B99D...714D00012
0 ETH0.000000120.00100036
Set Reward Ratio110764542025-03-09 2:49:07322 days ago1741488547IN
0x02c3B99D...714D00012
0 ETH0.000000110.00100037
Set Reward Ratio110574582025-03-08 16:15:55322 days ago1741450555IN
0x02c3B99D...714D00012
0 ETH0.000000120.00100038
Set Reward Ratio110346572025-03-08 3:35:53323 days ago1741404953IN
0x02c3B99D...714D00012
0 ETH0.000000130.00100038
Set Reward Ratio110148132025-03-07 16:34:25323 days ago1741365265IN
0x02c3B99D...714D00012
0 ETH0.000000820.00100033
Set Reward Ratio109926782025-03-07 4:16:35324 days ago1741320995IN
0x02c3B99D...714D00012
0 ETH0.000000110.00100037
Set Reward Ratio109709692025-03-06 16:12:57324 days ago1741277577IN
0x02c3B99D...714D00012
0 ETH0.000000320.00100039
Set Reward Ratio109475382025-03-06 3:11:55325 days ago1741230715IN
0x02c3B99D...714D00012
0 ETH0.000000110.00100042
Stake101937172025-02-16 16:24:33342 days ago1739723073IN
0x02c3B99D...714D00012
0 ETH0.000000320.00100051
Deposit Reward T...101725762025-02-16 4:39:51343 days ago1739680791IN
0x02c3B99D...714D00012
0 ETH0.00000010.00100035

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xf17B4017...bFf618dBE
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Staking20Base

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 20 runs

Other Settings:
london EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @author thirdweb

import "../extension/ContractMetadata.sol";
import "../extension/Multicall.sol";
import "../extension/Ownable.sol";
import "../extension/Staking20.sol";

import "../eip/interface/IERC20.sol";
import "../eip/interface/IERC20Metadata.sol";

import { CurrencyTransferLib } from "../lib/CurrencyTransferLib.sol";

/**
 *
 *  EXTENSION: Staking20
 *
 *  The `Staking20Base` smart contract implements Token staking mechanism.
 *  Allows users to stake their ERC-20 Tokens and earn rewards in form of another ERC-20 tokens.
 *
 *  Following features and implementation setup must be noted:
 *
 *      - ERC-20 Tokens from only one contract can be staked.
 *
 *      - Contract admin can choose to give out rewards by either transferring or minting the rewardToken,
 *        which is ideally a different ERC20 token. See {_mintRewards}.
 *
 *      - To implement custom logic for staking, reward calculation, etc. corresponding functions can be
 *        overridden from the extension `Staking20`.
 *
 *      - Ownership of the contract, with the ability to restrict certain functions to
 *        only be called by the contract's owner.
 *
 *      - Multicall capability to perform multiple actions atomically.
 *
 */

/// note: This contract is provided as a base contract.
//        This is to support a variety of use-cases that can be build on top of this base.
//
//        Additional functionality such as deposit functions, reward-minting, etc.
//        must be implemented by the deployer of this contract, as needed for their use-case.

contract Staking20Base is ContractMetadata, Multicall, Ownable, Staking20 {
    /// @dev ERC20 Reward Token address. See {_mintRewards} below.
    address public immutable rewardToken;

    /// @dev Total amount of reward tokens in the contract.
    uint256 private rewardTokenBalance;

    constructor(
        uint80 _timeUnit,
        address _defaultAdmin,
        uint256 _rewardRatioNumerator,
        uint256 _rewardRatioDenominator,
        address _stakingToken,
        address _rewardToken,
        address _nativeTokenWrapper
    )
        Staking20(
            _nativeTokenWrapper,
            _stakingToken,
            IERC20Metadata(_stakingToken).decimals(),
            IERC20Metadata(_rewardToken).decimals()
        )
    {
        _setupOwner(_defaultAdmin);
        _setStakingCondition(_timeUnit, _rewardRatioNumerator, _rewardRatioDenominator);

        require(_rewardToken != _stakingToken, "Reward Token and Staking Token can't be same.");
        rewardToken = _rewardToken;
    }

    /// @dev Lets the contract receive ether to unwrap native tokens.
    receive() external payable virtual {
        require(msg.sender == nativeTokenWrapper, "caller not native token wrapper.");
    }

    /// @dev Admin deposits reward tokens.
    function depositRewardTokens(uint256 _amount) external payable virtual nonReentrant {
        _depositRewardTokens(_amount); // override this for custom logic.
    }

    /// @dev Admin can withdraw excess reward tokens.
    function withdrawRewardTokens(uint256 _amount) external virtual nonReentrant {
        _withdrawRewardTokens(_amount); // override this for custom logic.
    }

    /// @notice View total rewards available in the staking contract.
    function getRewardTokenBalance() external view virtual override returns (uint256) {
        return rewardTokenBalance;
    }

    /*//////////////////////////////////////////////////////////////
                        Minting logic
    //////////////////////////////////////////////////////////////*/

    /**
     *  @dev    Mint ERC20 rewards to the staker. Override for custom logic.
     *
     *  @param _staker    Address for which to calculated rewards.
     *  @param _rewards   Amount of tokens to be given out as reward.
     *
     */
    function _mintRewards(address _staker, uint256 _rewards) internal virtual override {
        require(_rewards <= rewardTokenBalance, "Not enough reward tokens");
        rewardTokenBalance -= _rewards;
        CurrencyTransferLib.transferCurrencyWithWrapper(
            rewardToken,
            address(this),
            _staker,
            _rewards,
            nativeTokenWrapper
        );
    }

    /*//////////////////////////////////////////////////////////////
                        Other Internal functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Admin deposits reward tokens -- override for custom logic.
    function _depositRewardTokens(uint256 _amount) internal virtual {
        require(msg.sender == owner(), "Not authorized");

        address _rewardToken = rewardToken == CurrencyTransferLib.NATIVE_TOKEN ? nativeTokenWrapper : rewardToken;

        uint256 balanceBefore = IERC20(_rewardToken).balanceOf(address(this));
        CurrencyTransferLib.transferCurrencyWithWrapper(
            rewardToken,
            msg.sender,
            address(this),
            _amount,
            nativeTokenWrapper
        );
        uint256 actualAmount = IERC20(_rewardToken).balanceOf(address(this)) - balanceBefore;

        rewardTokenBalance += actualAmount;
    }

    /// @dev Admin can withdraw excess reward tokens -- override for custom logic.
    function _withdrawRewardTokens(uint256 _amount) internal virtual {
        require(msg.sender == owner(), "Not authorized");

        // to prevent locking of direct-transferred tokens
        rewardTokenBalance = _amount > rewardTokenBalance ? 0 : rewardTokenBalance - _amount;

        CurrencyTransferLib.transferCurrencyWithWrapper(
            rewardToken,
            address(this),
            msg.sender,
            _amount,
            nativeTokenWrapper
        );

        // The withdrawal shouldn't reduce staking token balance. `>=` accounts for any accidental transfers.
        address _stakingToken = stakingToken == CurrencyTransferLib.NATIVE_TOKEN ? nativeTokenWrapper : stakingToken;
        require(
            IERC20(_stakingToken).balanceOf(address(this)) >= stakingTokenBalance,
            "Staking token balance reduced."
        );
    }

    /// @dev Returns whether staking restrictions can be set in given execution context.
    function _canSetStakeConditions() internal view virtual override returns (bool) {
        return msg.sender == owner();
    }

    /// @dev Returns whether contract metadata can be set in the given execution context.
    function _canSetContractURI() internal view virtual override returns (bool) {
        return msg.sender == owner();
    }

    /// @dev Returns whether owner can be set in the given execution context.
    function _canSetOwner() internal view virtual override returns (bool) {
        return msg.sender == owner();
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @author thirdweb

import "./interface/IContractMetadata.sol";

/**
 *  @title   Contract Metadata
 *  @notice  Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
 *           for you contract.
 *           Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
 */

abstract contract ContractMetadata is IContractMetadata {
    /// @dev The sender is not authorized to perform the action
    error ContractMetadataUnauthorized();

    /// @notice Returns the contract metadata URI.
    string public override contractURI;

    /**
     *  @notice         Lets a contract admin set the URI for contract-level metadata.
     *  @dev            Caller should be authorized to setup contractURI, e.g. contract admin.
     *                  See {_canSetContractURI}.
     *                  Emits {ContractURIUpdated Event}.
     *
     *  @param _uri     keccak256 hash of the role. e.g. keccak256("TRANSFER_ROLE")
     */
    function setContractURI(string memory _uri) external override {
        if (!_canSetContractURI()) {
            revert ContractMetadataUnauthorized();
        }

        _setupContractURI(_uri);
    }

    /// @dev Lets a contract admin set the URI for contract-level metadata.
    function _setupContractURI(string memory _uri) internal {
        string memory prevURI = contractURI;
        contractURI = _uri;

        emit ContractURIUpdated(prevURI, _uri);
    }

    /// @dev Returns whether contract metadata can be set in the given execution context.
    function _canSetContractURI() internal view virtual returns (bool);
}

// SPDX-License-Identifier: Apache 2.0
pragma solidity ^0.8.0;

/// @author thirdweb

import "../lib/Address.sol";
import "./interface/IMulticall.sol";

/**
 * @dev Provides a function to batch together multiple calls in a single external call.
 *
 * _Available since v4.1._
 */
contract Multicall is IMulticall {
    /**
     *  @notice Receives and executes a batch of function calls on this contract.
     *  @dev Receives and executes a batch of function calls on this contract.
     *
     *  @param data The bytes data that makes up the batch of function calls to execute.
     *  @return results The bytes data that makes up the result of the batch of function calls executed.
     */
    function multicall(bytes[] calldata data) external returns (bytes[] memory results) {
        results = new bytes[](data.length);
        address sender = _msgSender();
        bool isForwarder = msg.sender != sender;
        for (uint256 i = 0; i < data.length; i++) {
            if (isForwarder) {
                results[i] = Address.functionDelegateCall(address(this), abi.encodePacked(data[i], sender));
            } else {
                results[i] = Address.functionDelegateCall(address(this), data[i]);
            }
        }
        return results;
    }

    /// @notice Returns the sender in the given execution context.
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @author thirdweb

import "./interface/IOwnable.sol";

/**
 *  @title   Ownable
 *  @notice  Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
 *           who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
 *           information about who the contract's owner is.
 */

abstract contract Ownable is IOwnable {
    /// @dev The sender is not authorized to perform the action
    error OwnableUnauthorized();

    /// @dev Owner of the contract (purpose: OpenSea compatibility)
    address private _owner;

    /// @dev Reverts if caller is not the owner.
    modifier onlyOwner() {
        if (msg.sender != _owner) {
            revert OwnableUnauthorized();
        }
        _;
    }

    /**
     *  @notice Returns the owner of the contract.
     */
    function owner() public view override returns (address) {
        return _owner;
    }

    /**
     *  @notice Lets an authorized wallet set a new owner for the contract.
     *  @param _newOwner The address to set as the new owner of the contract.
     */
    function setOwner(address _newOwner) external override {
        if (!_canSetOwner()) {
            revert OwnableUnauthorized();
        }
        _setupOwner(_newOwner);
    }

    /// @dev Lets a contract admin set a new owner for the contract. The new owner must be a contract admin.
    function _setupOwner(address _newOwner) internal {
        address _prevOwner = _owner;
        _owner = _newOwner;

        emit OwnerUpdated(_prevOwner, _newOwner);
    }

    /// @dev Returns whether owner can be set in the given execution context.
    function _canSetOwner() internal view virtual returns (bool);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

/// @author thirdweb

import "../external-deps/openzeppelin/security/ReentrancyGuard.sol";
import "../external-deps/openzeppelin/utils/math/SafeMath.sol";
import "../eip/interface/IERC20.sol";
import { CurrencyTransferLib } from "../lib/CurrencyTransferLib.sol";

import "./interface/IStaking20.sol";

abstract contract Staking20 is ReentrancyGuard, IStaking20 {
    /*///////////////////////////////////////////////////////////////
                            State variables / Mappings
    //////////////////////////////////////////////////////////////*/

    /// @dev The address of the native token wrapper contract.
    address internal immutable nativeTokenWrapper;

    ///@dev Address of ERC20 contract -- staked tokens belong to this contract.
    address public immutable stakingToken;

    /// @dev Decimals of staking token.
    uint16 public immutable stakingTokenDecimals;

    /// @dev Decimals of reward token.
    uint16 public immutable rewardTokenDecimals;

    ///@dev Next staking condition Id. Tracks number of conditon updates so far.
    uint64 private nextConditionId;

    /// @dev Total amount of tokens staked in the contract.
    uint256 public stakingTokenBalance;

    /// @dev Mapping address to if they have staked.
    mapping(address => bool) public hasStaked;

    ///@dev Mapping staker address to Staker struct. See {struct IStaking20.Staker}.
    mapping(address => Staker) public stakers;

    ///@dev Mapping from condition Id to staking condition. See {struct IStaking721.StakingCondition}
    mapping(uint256 => StakingCondition) private stakingConditions;

    constructor(
        address _nativeTokenWrapper,
        address _stakingToken,
        uint16 _stakingTokenDecimals,
        uint16 _rewardTokenDecimals
    ) ReentrancyGuard() {
        require(_stakingToken != address(0) && _nativeTokenWrapper != address(0), "address 0");
        require(_stakingTokenDecimals != 0 && _rewardTokenDecimals != 0, "decimals 0");

        nativeTokenWrapper = _nativeTokenWrapper;
        stakingToken = _stakingToken;
        stakingTokenDecimals = _stakingTokenDecimals;
        rewardTokenDecimals = _rewardTokenDecimals;
    }

    /*///////////////////////////////////////////////////////////////
                        External/Public Functions
    //////////////////////////////////////////////////////////////*/

    /**
     *  @notice    Stake ERC20 Tokens.
     *
     *  @dev       See {_stake}. Override that to implement custom logic.
     */
    function stake() external nonReentrant {
        require(!hasStaked[msg.sender], "Already staked");
        _stake();
        hasStaked[msg.sender] = true;
    }

    /**
     *  @notice    Withdraw staked ERC20 tokens.
     *
     *  @dev       See {_withdraw}. Override that to implement custom logic.
     */
    function withdraw() external nonReentrant {
        require(hasStaked[msg.sender], "Not staked");
        _withdraw();
        hasStaked[msg.sender] = false;
    }

    /**
     *  @notice    Claim accumulated rewards.
     *
     *  @dev       See {_claimRewards}. Override that to implement custom logic.
     *             See {_calculateRewards} for reward-calculation logic.
     */
    function claimRewards() external nonReentrant {
        _claimRewards();
    }

    /**
     *  @notice  Set time unit. Set as a number of seconds.
     *           Could be specified as -- x * 1 hours, x * 1 days, etc.
     *
     *  @dev     Only admin/authorized-account can call it.
     *
     *  @param _timeUnit    New time unit.
     */
    function setTimeUnit(uint80 _timeUnit) external virtual {
        if (!_canSetStakeConditions()) {
            revert("Not authorized");
        }

        StakingCondition memory condition = stakingConditions[nextConditionId - 1];
        require(_timeUnit != condition.timeUnit, "Time-unit unchanged.");

        _setStakingCondition(_timeUnit, condition.rewardRatioNumerator, condition.rewardRatioDenominator);

        emit UpdatedTimeUnit(condition.timeUnit, _timeUnit);
    }

    /**
     *  @notice  Set rewards per unit of time.
     *           Interpreted as (numerator/denominator) rewards per second/per day/etc based on time-unit.
     *
     *           For e.g., ratio of 1/20 would mean 1 reward token for every 20 tokens staked.
     *
     *  @dev     Only admin/authorized-account can call it.
     *
     *  @param _numerator    Reward ratio numerator.
     *  @param _denominator  Reward ratio denominator.
     */
    function setRewardRatio(uint256 _numerator, uint256 _denominator) external virtual {
        if (!_canSetStakeConditions()) {
            revert("Not authorized");
        }

        StakingCondition memory condition = stakingConditions[nextConditionId - 1];
        require(
            _numerator != condition.rewardRatioNumerator || _denominator != condition.rewardRatioDenominator,
            "Reward ratio unchanged."
        );
        _setStakingCondition(condition.timeUnit, _numerator, _denominator);

        emit UpdatedRewardRatio(
            condition.rewardRatioNumerator,
            _numerator,
            condition.rewardRatioDenominator,
            _denominator
        );
    }

    /**
     *  @notice View amount staked and rewards for a user.
     *
     *  @param _staker          Address for which to calculated rewards.
     *  @return _tokensStaked   Amount of tokens staked.
     *  @return _rewards        Available reward amount.
     */
    function getStakeInfo(address _staker) external view virtual returns (uint256 _tokensStaked, uint256 _rewards) {
        _tokensStaked = stakers[_staker].amountStaked;
        _rewards = _availableRewards(_staker);
    }

    function getTimeUnit() public view returns (uint256 _timeUnit) {
        _timeUnit = stakingConditions[nextConditionId - 1].timeUnit;
    }

    function getRewardRatio() public view returns (uint256 _numerator, uint256 _denominator) {
        _numerator = stakingConditions[nextConditionId - 1].rewardRatioNumerator;
        _denominator = stakingConditions[nextConditionId - 1].rewardRatioDenominator;
    }

    /*///////////////////////////////////////////////////////////////
                            Internal Functions
    //////////////////////////////////////////////////////////////*/

    /// @dev Staking logic. Override to add custom logic.
    function _stake() internal virtual {
        stakers[_stakeMsgSender()].timeOfLastUpdate = uint80(block.timestamp);
        stakers[_stakeMsgSender()].conditionIdOflastUpdate = nextConditionId - 1;

        stakers[_stakeMsgSender()].amountStaked = 1000000000000000000;
        stakingTokenBalance += 1000000000000000000;

        emit TokensStaked(_stakeMsgSender(), 1000000000000000000);
    }

    /// @dev Withdraw logic. Override to add custom logic.
    function _withdraw() internal virtual {
        _updateUnclaimedRewardsForStaker(_stakeMsgSender());

        stakers[_stakeMsgSender()].amountStaked = 0;
        stakingTokenBalance -= 1000000000000000000;

        emit TokensWithdrawn(_stakeMsgSender(), 1000000000000000000);
    }

    /// @dev Logic for claiming rewards. Override to add custom logic.
    function _claimRewards() internal virtual {
        uint256 rewards = stakers[_stakeMsgSender()].unclaimedRewards + _calculateRewards(_stakeMsgSender());

        require(rewards != 0, "No rewards");

        stakers[_stakeMsgSender()].timeOfLastUpdate = uint80(block.timestamp);
        stakers[_stakeMsgSender()].unclaimedRewards = 0;
        stakers[_stakeMsgSender()].conditionIdOflastUpdate = nextConditionId - 1;

        _mintRewards(_stakeMsgSender(), rewards);

        emit RewardsClaimed(_stakeMsgSender(), rewards);
    }

    /// @dev View available rewards for a user.
    function _availableRewards(address _staker) internal view virtual returns (uint256 _rewards) {
        if (stakers[_staker].amountStaked == 0) {
            _rewards = stakers[_staker].unclaimedRewards;
        } else {
            _rewards = stakers[_staker].unclaimedRewards + _calculateRewards(_staker);
        }
    }

    /// @dev Update unclaimed rewards for a users. Called for every state change for a user.
    function _updateUnclaimedRewardsForStaker(address _staker) internal virtual {
        uint256 rewards = _calculateRewards(_staker);
        stakers[_staker].unclaimedRewards += rewards;
        stakers[_staker].timeOfLastUpdate = uint80(block.timestamp);
        stakers[_staker].conditionIdOflastUpdate = nextConditionId - 1;
    }

    /// @dev Set staking conditions.
    function _setStakingCondition(uint80 _timeUnit, uint256 _numerator, uint256 _denominator) internal virtual {
        require(_denominator != 0, "divide by 0");
        require(_timeUnit != 0, "time-unit can't be 0");
        uint256 conditionId = nextConditionId;
        nextConditionId += 1;

        stakingConditions[conditionId] = StakingCondition({
            timeUnit: _timeUnit,
            rewardRatioNumerator: _numerator,
            rewardRatioDenominator: _denominator,
            startTimestamp: uint80(block.timestamp),
            endTimestamp: 0
        });

        if (conditionId > 0) {
            stakingConditions[conditionId - 1].endTimestamp = uint80(block.timestamp);
        }
    }

    /// @dev Calculate rewards for a staker.
    function _calculateRewards(address _staker) internal view virtual returns (uint256 _rewards) {
        Staker memory staker = stakers[_staker];

        uint256 _stakerConditionId = staker.conditionIdOflastUpdate;
        uint256 _nextConditionId = nextConditionId;

        for (uint256 i = _stakerConditionId; i < _nextConditionId; i += 1) {
            StakingCondition memory condition = stakingConditions[i];

            uint256 startTime = i != _stakerConditionId ? condition.startTimestamp : staker.timeOfLastUpdate;
            uint256 endTime = condition.endTimestamp != 0 ? condition.endTimestamp : block.timestamp;

            (bool noOverflowProduct, uint256 rewardsProduct) = SafeMath.tryMul(
                (endTime - startTime) * staker.amountStaked,
                condition.rewardRatioNumerator
            );
            (bool noOverflowSum, uint256 rewardsSum) = SafeMath.tryAdd(
                _rewards,
                (rewardsProduct / condition.timeUnit) / condition.rewardRatioDenominator
            );

            _rewards = noOverflowProduct && noOverflowSum ? rewardsSum : _rewards;
        }

        (, _rewards) = SafeMath.tryMul(_rewards, 10 ** rewardTokenDecimals);

        _rewards /= (10 ** stakingTokenDecimals);
    }

    /*////////////////////////////////////////////////////////////////////
        Optional hooks that can be implemented in the derived contract
    ///////////////////////////////////////////////////////////////////*/

    /// @dev Exposes the ability to override the msg sender -- support ERC2771.
    function _stakeMsgSender() internal virtual returns (address) {
        return msg.sender;
    }

    /*///////////////////////////////////////////////////////////////
        Virtual functions to be implemented in derived contract
    //////////////////////////////////////////////////////////////*/

    /**
     *  @notice View total rewards available in the staking contract.
     *
     */
    function getRewardTokenBalance() external view virtual returns (uint256 _rewardsAvailableInContract);

    /**
     *  @dev    Mint/Transfer ERC20 rewards to the staker. Must override.
     *
     *  @param _staker    Address for which to calculated rewards.
     *  @param _rewards   Amount of tokens to be given out as reward.
     *
     *  For example, override as below to mint ERC20 rewards:
     *
     * ```
     *  function _mintRewards(address _staker, uint256 _rewards) internal override {
     *
     *      TokenERC20(rewardTokenAddress).mintTo(_staker, _rewards);
     *
     *  }
     * ```
     */
    function _mintRewards(address _staker, uint256 _rewards) internal virtual;

    /**
     *  @dev    Returns whether staking restrictions can be set in given execution context.
     *          Must override.
     *
     *
     *  For example, override as below to restrict access to admin:
     *
     * ```
     *  function _canSetStakeConditions() internal override {
     *
     *      return msg.sender == adminAddress;
     *
     *  }
     * ```
     */
    function _canSetStakeConditions() internal view virtual returns (bool);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/**
 * @title ERC20Metadata interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface IERC20Metadata {
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @author thirdweb

// Helper interfaces
import { IWETH } from "../infra/interface/IWETH.sol";
import { SafeERC20, IERC20 } from "../external-deps/openzeppelin/token/ERC20/utils/SafeERC20.sol";

library CurrencyTransferLib {
    using SafeERC20 for IERC20;

    error CurrencyTransferLibMismatchedValue(uint256 expected, uint256 actual);
    error CurrencyTransferLibFailedNativeTransfer(address recipient, uint256 value);

    /// @dev The address interpreted as native token of the chain.
    address public constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @dev Transfers a given amount of currency.
    function transferCurrency(address _currency, address _from, address _to, uint256 _amount) internal {
        if (_amount == 0) {
            return;
        }

        if (_currency == NATIVE_TOKEN) {
            safeTransferNativeToken(_to, _amount);
        } else {
            safeTransferERC20(_currency, _from, _to, _amount);
        }
    }

    /// @dev Transfers a given amount of currency. (With native token wrapping)
    function transferCurrencyWithWrapper(
        address _currency,
        address _from,
        address _to,
        uint256 _amount,
        address _nativeTokenWrapper
    ) internal {
        if (_amount == 0) {
            return;
        }

        if (_currency == NATIVE_TOKEN) {
            if (_from == address(this)) {
                // withdraw from weth then transfer withdrawn native token to recipient
                IWETH(_nativeTokenWrapper).withdraw(_amount);
                safeTransferNativeTokenWithWrapper(_to, _amount, _nativeTokenWrapper);
            } else if (_to == address(this)) {
                // store native currency in weth
                if (_amount != msg.value) {
                    revert CurrencyTransferLibMismatchedValue(msg.value, _amount);
                }
                IWETH(_nativeTokenWrapper).deposit{ value: _amount }();
            } else {
                safeTransferNativeTokenWithWrapper(_to, _amount, _nativeTokenWrapper);
            }
        } else {
            safeTransferERC20(_currency, _from, _to, _amount);
        }
    }

    /// @dev Transfer `amount` of ERC20 token from `from` to `to`.
    function safeTransferERC20(address _currency, address _from, address _to, uint256 _amount) internal {
        if (_from == _to) {
            return;
        }

        if (_from == address(this)) {
            IERC20(_currency).safeTransfer(_to, _amount);
        } else {
            IERC20(_currency).safeTransferFrom(_from, _to, _amount);
        }
    }

    /// @dev Transfers `amount` of native token to `to`.
    function safeTransferNativeToken(address to, uint256 value) internal {
        // solhint-disable avoid-low-level-calls
        // slither-disable-next-line low-level-calls
        (bool success, ) = to.call{ value: value }("");
        if (!success) {
            revert CurrencyTransferLibFailedNativeTransfer(to, value);
        }
    }

    /// @dev Transfers `amount` of native token to `to`. (With native token wrapping)
    function safeTransferNativeTokenWithWrapper(address to, uint256 value, address _nativeTokenWrapper) internal {
        // solhint-disable avoid-low-level-calls
        // slither-disable-next-line low-level-calls
        (bool success, ) = to.call{ value: value }("");
        if (!success) {
            IWETH(_nativeTokenWrapper).deposit{ value: value }();
            IERC20(_nativeTokenWrapper).safeTransfer(to, value);
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @author thirdweb

/**
 *  Thirdweb's `ContractMetadata` is a contract extension for any base contracts. It lets you set a metadata URI
 *  for you contract.
 *
 *  Additionally, `ContractMetadata` is necessary for NFT contracts that want royalties to get distributed on OpenSea.
 */

interface IContractMetadata {
    /// @dev Returns the metadata URI of the contract.
    function contractURI() external view returns (string memory);

    /**
     *  @dev Sets contract URI for the storefront-level metadata of the contract.
     *       Only module admin can call this function.
     */
    function setContractURI(string calldata _uri) external;

    /// @dev Emitted when the contract URI is updated.
    event ContractURIUpdated(string prevURI, string newURI);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.1;

/// @author thirdweb, OpenZeppelin Contracts (v4.9.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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 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://consensys.net/diligence/blog/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.8.0/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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{ value: value }(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @author thirdweb

/**
 * @dev Provides a function to batch together multiple calls in a single external call.
 *
 * _Available since v4.1._
 */
interface IMulticall {
    /**
     * @dev Receives and executes a batch of function calls on this contract.
     */
    function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

/// @author thirdweb

/**
 *  Thirdweb's `Ownable` is a contract extension to be used with any base contract. It exposes functions for setting and reading
 *  who the 'owner' of the inheriting smart contract is, and lets the inheriting contract perform conditional logic that uses
 *  information about who the contract's owner is.
 */

interface IOwnable {
    /// @dev Returns the owner of the contract.
    function owner() external view returns (address);

    /// @dev Lets a module admin set a new owner for the contract. The new owner must be a module admin.
    function setOwner(address _newOwner) external;

    /// @dev Emitted when a new Owner is set.
    event OwnerUpdated(address indexed prevOwner, address indexed newOwner);
}

File 13 of 17 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

abstract contract ReentrancyGuard {
    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.
     */
    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;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.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 generally not needed starting with Solidity 0.8, since 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 subtraction 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;
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

/// @author thirdweb

interface IStaking20 {
    /// @dev Emitted when tokens are staked.
    event TokensStaked(address indexed staker, uint256 amount);

    /// @dev Emitted when a tokens are withdrawn.
    event TokensWithdrawn(address indexed staker, uint256 amount);

    /// @dev Emitted when a staker claims staking rewards.
    event RewardsClaimed(address indexed staker, uint256 rewardAmount);

    /// @dev Emitted when contract admin updates timeUnit.
    event UpdatedTimeUnit(uint256 oldTimeUnit, uint256 newTimeUnit);

    /// @dev Emitted when contract admin updates rewardsPerUnitTime.
    event UpdatedRewardRatio(
        uint256 oldNumerator,
        uint256 newNumerator,
        uint256 oldDenominator,
        uint256 newDenominator
    );

    /// @dev Emitted when contract admin updates minimum staking amount.
    event UpdatedMinStakeAmount(uint256 oldAmount, uint256 newAmount);

    /**
     *  @notice Staker Info.
     *
     *  @param amountStaked             Total number of tokens staked by the staker.
     *
     *  @param timeOfLastUpdate         Last reward-update timestamp.
     *
     *  @param unclaimedRewards         Rewards accumulated but not claimed by user yet.
     *
     *  @param conditionIdOflastUpdate  Condition-Id when rewards were last updated for user.
     */
    struct Staker {
        uint128 timeOfLastUpdate;
        uint64 conditionIdOflastUpdate;
        uint256 amountStaked;
        uint256 unclaimedRewards;
    }

    /**
     *  @notice Staking Condition.
     *
     *  @param timeUnit                 Unit of time specified in number of seconds. Can be set as 1 seconds, 1 days, 1 hours, etc.
     *
     *  @param rewardRatioNumerator     Rewards ratio is the number of reward tokens for a number of staked tokens,
     *                                  per unit of time.
     *
     *  @param rewardRatioDenominator   Rewards ratio is the number of reward tokens for a number of staked tokens,
     *                                  per unit of time.
     *
     *  @param startTimestamp           Condition start timestamp.
     *
     *  @param endTimestamp             Condition end timestamp.
     */
    struct StakingCondition {
        uint80 timeUnit;
        uint80 startTimestamp;
        uint80 endTimestamp;
        uint256 rewardRatioNumerator;
        uint256 rewardRatioDenominator;
    }

    /**
     *  @notice Stake ERC721 Tokens.
     *
     */
    function stake() external;

    /**
     *  @notice Withdraw staked tokens.
     *
     */
    function withdraw() external;

    /**
     *  @notice Claim accumulated rewards.
     *
     */
    function claimRewards() external;

    /**
     *  @notice View amount staked and total rewards for a user.
     *
     *  @param staker    Address for which to calculated rewards.
     */
    function getStakeInfo(address staker) external view returns (uint256 _tokensStaked, uint256 _rewards);
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 amount) external;

    function transfer(address to, uint256 value) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../../../../../eip/interface/IERC20.sol";
import { Address } from "../../../../../lib/Address.sol";

/**
 * @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");
        }
    }
}

Settings
{
  "remappings": [
    "@uniswap/v3-core/contracts/=lib/v3-core/contracts/",
    "@uniswap/v3-periphery/contracts/=lib/v3-periphery/contracts/",
    "@uniswap/swap-router-contracts/contracts/=lib/swap-router-contracts/contracts/",
    "@chainlink/=lib/chainlink/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@ds-test/=lib/ds-test/src/",
    "@std/=lib/forge-std/src/",
    "contracts/=contracts/",
    "erc721a-upgradeable/=lib/ERC721A-Upgradeable/",
    "erc721a/=lib/ERC721A/",
    "@thirdweb-dev/dynamic-contracts/=lib/dynamic-contracts/",
    "lib/sstore2/=lib/dynamic-contracts/lib/sstore2/",
    "solady/=lib/solady/",
    "@seaport/=lib/seaport/contracts/",
    "seaport-types/=lib/seaport/lib/seaport-types/",
    "seaport-core/=lib/seaport/lib/seaport-core/",
    "@rari-capital/solmate/=lib/seaport/lib/solmate/",
    "ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/",
    "ERC721A/=lib/ERC721A/contracts/",
    "chainlink/=lib/chainlink/contracts/",
    "ds-test/=lib/ds-test/src/",
    "dynamic-contracts/=lib/dynamic-contracts/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "murky/=lib/murky/src/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "seaport-sol/=lib/seaport-sol/src/",
    "seaport/=lib/seaport/",
    "solarray/=lib/seaport-sol/lib/solarray/src/",
    "solmate/=lib/seaport/lib/solmate/src/",
    "sstore2/=lib/dynamic-contracts/lib/sstore2/contracts/",
    "swap-router-contracts/=lib/swap-router-contracts/contracts/",
    "v3-core/=lib/v3-core/",
    "v3-periphery/=lib/v3-periphery/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 20
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"uint80","name":"_timeUnit","type":"uint80"},{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"uint256","name":"_rewardRatioNumerator","type":"uint256"},{"internalType":"uint256","name":"_rewardRatioDenominator","type":"uint256"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_nativeTokenWrapper","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ContractMetadataUnauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"CurrencyTransferLibMismatchedValue","type":"error"},{"inputs":[],"name":"OwnableUnauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"prevURI","type":"string"},{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prevOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardAmount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAmount","type":"uint256"}],"name":"UpdatedMinStakeAmount","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldNumerator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newNumerator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldDenominator","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDenominator","type":"uint256"}],"name":"UpdatedRewardRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldTimeUnit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTimeUnit","type":"uint256"}],"name":"UpdatedTimeUnit","type":"event"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositRewardTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getRewardRatio","outputs":[{"internalType":"uint256","name":"_numerator","type":"uint256"},{"internalType":"uint256","name":"_denominator","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"getStakeInfo","outputs":[{"internalType":"uint256","name":"_tokensStaked","type":"uint256"},{"internalType":"uint256","name":"_rewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimeUnit","outputs":[{"internalType":"uint256","name":"_timeUnit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasStaked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardTokenDecimals","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_uri","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numerator","type":"uint256"},{"internalType":"uint256","name":"_denominator","type":"uint256"}],"name":"setRewardRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint80","name":"_timeUnit","type":"uint80"}],"name":"setTimeUnit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakers","outputs":[{"internalType":"uint128","name":"timeOfLastUpdate","type":"uint128"},{"internalType":"uint64","name":"conditionIdOflastUpdate","type":"uint64"},{"internalType":"uint256","name":"amountStaked","type":"uint256"},{"internalType":"uint256","name":"unclaimedRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingTokenDecimals","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawRewardTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

0x6101206040523480156200001257600080fd5b5060405162002ef838038062002ef88339810160408190526200003591620004c9565b8083846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000076573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009c919062000559565b60ff16846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000104919062000559565b600160025560ff166001600160a01b038316158015906200012d57506001600160a01b03841615155b6200016b5760405162461bcd60e51b815260206004820152600960248201526806164647265737320360bc1b60448201526064015b60405180910390fd5b61ffff82161580159062000182575061ffff811615155b620001bd5760405162461bcd60e51b815260206004820152600a6024820152690646563696d616c7320360b41b604482015260640162000162565b6001600160a01b039384166080529190921660a05261ffff91821660c0521660e052620001ea866200028a565b620001f7878686620002dc565b826001600160a01b0316826001600160a01b031603620002705760405162461bcd60e51b815260206004820152602d60248201527f52657761726420546f6b656e20616e64205374616b696e6720546f6b656e206360448201526c30b713ba1031329039b0b6b29760991b606482015260840162000162565b506001600160a01b03166101005250620005e19350505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a35050565b806000036200031c5760405162461bcd60e51b815260206004820152600b60248201526a064697669646520627920360ac1b604482015260640162000162565b826001600160501b0316600003620003775760405162461bcd60e51b815260206004820152601460248201527f74696d652d756e69742063616e27742062652030000000000000000000000000604482015260640162000162565b600380546001600160401b03169060019060006200039683856200059b565b82546001600160401b039182166101009390930a9283029190920219909116179055506040805160a0810182526001600160501b03808716825242811660208084019182526000848601818152606086018a8152608087018a815289845260079094529690912094518554935191518516600160a01b02600160a01b600160f01b03199286166a0100000000000000000000026001600160a01b0319909516919095161792909217919091169190911782559151600182015590516002909101558015620004a657426007600062000470600185620005c5565b815260200190815260200160002060000160146101000a8154816001600160501b0302191690836001600160501b031602179055505b50505050565b80516001600160a01b0381168114620004c457600080fd5b919050565b600080600080600080600060e0888a031215620004e557600080fd5b87516001600160501b0381168114620004fd57600080fd5b96506200050d60208901620004ac565b955060408801519450606088015193506200052b60808901620004ac565b92506200053b60a08901620004ac565b91506200054b60c08901620004ac565b905092959891949750929550565b6000602082840312156200056c57600080fd5b815160ff811681146200057e57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b6001600160401b03818116838216019080821115620005be57620005be62000585565b5092915050565b81810381811115620005db57620005db62000585565b92915050565b60805160a05160c05160e05161010051612870620006886000396000818161052a01528181610f9e01528181610fe2015281816110a0015281816115c80152611b560152600081816103ab0152611a7f01526000818161043f0152611ab301526000818161024001528181611614015261165801526000818161012301528181611008015281816110c4015281816115ec0152818161167e0152611b7a01526128706000f3fe6080604052600436106101135760003560e01c80621b79341461019c57806313af4035146101bc57806316c621e0146101dc578063372500ab146101ef5780633a4b66f1146102045780633ccfd60b1461021957806372f702f31461022e5780638caaa271146102785780638da5cb5b1461029c5780639168ae72146102b1578063938e3d7b1461033a57806393ce53431461035a57806397e1b4bc1461036f5780639bdcecd114610399578063ac9650d8146103e0578063b218f0691461040d578063b9f7a7b51461042d578063c345315314610461578063c93c8f3414610481578063cb43b2dd146104c1578063d68124c7146104e1578063e8a3d485146104f6578063f7c618c11461051857600080fd5b3661019757336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101955760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206e6f74206e617469766520746f6b656e20777261707065722e60448201526064015b60405180910390fd5b005b600080fd5b3480156101a857600080fd5b506101956101b736600461210a565b61054c565b3480156101c857600080fd5b506101956101d736600461212c565b6106b6565b6101956101ea366004612155565b6106e7565b3480156101fb57600080fd5b5061019561071d565b34801561021057600080fd5b50610195610751565b34801561022557600080fd5b506101956107f1565b34801561023a57600080fd5b506102627f000000000000000000000000000000000000000000000000000000000000000081565b60405161026f919061216e565b60405180910390f35b34801561028457600080fd5b5061028e60045481565b60405190815260200161026f565b3480156102a857600080fd5b50610262610888565b3480156102bd57600080fd5b506103086102cc36600461212c565b6006602052600090815260409020805460018201546002909201546001600160801b03821692600160801b9092046001600160401b0316919084565b604080516001600160801b0390951685526001600160401b03909316602085015291830152606082015260800161026f565b34801561034657600080fd5b50610195610355366004612198565b610897565b34801561036657600080fd5b5060085461028e565b34801561037b57600080fd5b506103846108c5565b6040805192835260208301919091520161026f565b3480156103a557600080fd5b506103cd7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff909116815260200161026f565b3480156103ec57600080fd5b506104006103fb366004612248565b61094b565b60405161026f919061230c565b34801561041957600080fd5b50610195610428366004612370565b610ab1565b34801561043957600080fd5b506103cd7f000000000000000000000000000000000000000000000000000000000000000081565b34801561046d57600080fd5b5061038461047c36600461212c565b610c05565b34801561048d57600080fd5b506104b161049c36600461212c565b60056020526000908152604090205460ff1681565b604051901515815260200161026f565b3480156104cd57600080fd5b506101956104dc366004612155565b610c32565b3480156104ed57600080fd5b5061028e610c60565b34801561050257600080fd5b5061050b610ca8565b60405161026f9190612399565b34801561052457600080fd5b506102627f000000000000000000000000000000000000000000000000000000000000000081565b610554610d36565b6105705760405162461bcd60e51b815260040161018c906123ac565b6003546000906007908290610590906001906001600160401b03166123ea565b6001600160401b031681526020808201929092526040908101600020815160a08101835281546001600160501b038082168352600160501b8204811695830195909552600160a01b900490931691830191909152600181015460608301819052600290910154608083015290915083141580610610575080608001518214155b6106565760405162461bcd60e51b81526020600482015260176024820152762932bbb0b932103930ba34b7903ab731b430b733b2b21760491b604482015260640161018c565b8051610663908484610d59565b60608082015160808084015160408051938452602084018890528301529181018490527feb6684a1e7c9bd2adc792fb253558f022bcbef39fb6ad31dc58cdfefdd5b5190910160405180910390a1505050565b6106be610d36565b6106db576040516316ccb9cb60e11b815260040160405180910390fd5b6106e481610f10565b50565b60028054036107085760405162461bcd60e51b815260040161018c90612411565b6002805561071581610f62565b506001600255565b600280540361073e5760405162461bcd60e51b815260040161018c90612411565b6002805561074a611181565b6001600255565b60028054036107725760405162461bcd60e51b815260040161018c90612411565b600280553360009081526005602052604090205460ff16156107c75760405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481cdd185ad95960921b604482015260640161018c565b6107cf6112a7565b336000908152600560205260409020805460ff19166001908117909155600255565b60028054036108125760405162461bcd60e51b815260040161018c90612411565b600280553360009081526005602052604090205460ff166108625760405162461bcd60e51b815260206004820152600a602482015269139bdd081cdd185ad95960b21b604482015260640161018c565b61086a611387565b336000908152600560205260409020805460ff191690556001600255565b6001546001600160a01b031690565b61089f610d36565b6108bc57604051639f7f092560e01b815260040160405180910390fd5b6106e4816113fe565b600354600090819060079082906108e7906001906001600160401b03166123ea565b6001600160401b03168152602001908152602001600020600101549150600760006001600360009054906101000a90046001600160401b031661092a91906123ea565b6001600160401b031681526020019081526020016000206002015490509091565b6060816001600160401b0381111561096557610965612182565b60405190808252806020026020018201604052801561099857816020015b60608152602001906001900390816109835790505b509050336000805b84811015610aa7578115610a1f576109fd308787848181106109c4576109c4612448565b90506020028101906109d6919061245e565b866040516020016109e9939291906124a4565b6040516020818303038152906040526114cd565b848281518110610a0f57610a0f612448565b6020026020010181905250610a9f565b610a8130878784818110610a3557610a35612448565b9050602002810190610a47919061245e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114cd92505050565b848281518110610a9357610a93612448565b60200260200101819052505b6001016109a0565b5050505b92915050565b610ab9610d36565b610ad55760405162461bcd60e51b815260040161018c906123ac565b6003546000906007908290610af5906001906001600160401b03166123ea565b6001600160401b031681526020808201929092526040908101600020815160a08101835281546001600160501b03808216808452600160501b8304821696840196909652600160a01b9091048116938201939093526001820154606082015260029091015460808201529250831603610ba75760405162461bcd60e51b81526020600482015260146024820152732a34b6b296bab734ba103ab731b430b733b2b21760611b604482015260640161018c565b610bba8282606001518360800151610d59565b8051604080516001600160501b03928316815291841660208301527fd968de290ed68f978b9e4816f7d4be9ef46189fe8eeb3eeb86199e7229cf2de091015b60405180910390a15050565b6001600160a01b03811660009081526006602052604081206001015490610c2b836114f9565b9050915091565b6002805403610c535760405162461bcd60e51b815260040161018c90612411565b6002805561071581611569565b6003546000906007908290610c80906001906001600160401b03166123ea565b6001600160401b031681526020810191909152604001600020546001600160501b0316919050565b60008054610cb5906124c5565b80601f0160208091040260200160405190810160405280929190818152602001828054610ce1906124c5565b8015610d2e5780601f10610d0357610100808354040283529160200191610d2e565b820191906000526020600020905b815481529060010190602001808311610d1157829003601f168201915b505050505081565b6000610d40610888565b6001600160a01b0316336001600160a01b031614905090565b80600003610d975760405162461bcd60e51b815260206004820152600b60248201526a064697669646520627920360ac1b604482015260640161018c565b826001600160501b0316600003610de75760405162461bcd60e51b8152602060048201526014602482015273074696d652d756e69742063616e277420626520360641b604482015260640161018c565b600380546001600160401b0316906001906000610e0483856124ff565b82546001600160401b039182166101009390930a9283029190920219909116179055506040805160a0810182526001600160501b03808716825242811660208084019182526000848601818152606086018a8152608087018a815289845260079094529690912094518554935191518516600160a01b02600160a01b600160f01b0319928616600160501b026001600160a01b0319909516919095161792909217919091169190911782559151600182015590516002909101558015610f0a574260076000610ed460018561251f565b815260200190815260200160002060000160146101000a8154816001600160501b0302191690836001600160501b031602179055505b50505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a35050565b610f6a610888565b6001600160a01b0316336001600160a01b031614610f9a5760405162461bcd60e51b815260040161018c906123ac565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611006577f0000000000000000000000000000000000000000000000000000000000000000611028565b7f00000000000000000000000000000000000000000000000000000000000000005b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611058919061216e565b602060405180830381865afa158015611075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110999190612532565b90506110e87f00000000000000000000000000000000000000000000000000000000000000003330867f0000000000000000000000000000000000000000000000000000000000000000611762565b600081836001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611117919061216e565b602060405180830381865afa158015611134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111589190612532565b611162919061251f565b90508060086000828254611176919061254b565b909155505050505050565b600061118c336118b7565b336000908152600660205260409020600201546111a9919061254b565b9050806000036111e85760405162461bcd60e51b815260206004820152600a6024820152694e6f207265776172647360b01b604482015260640161018c565b33600090815260066020526040812080546001600160801b031916426001600160501b03161781556002015560035461122c906001906001600160401b03166123ea565b33600081815260066020526040902080546001600160401b0393909316600160801b02600160801b600160c01b03199093169290921790915561126f9082611aec565b60405181815233907ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe9060200160405180910390a250565b33600090815260066020526040902080546001600160801b031916426001600160501b03161790556003546112e7906001906001600160401b03166123ea565b33600090815260066020526040812080546001600160401b0393909316600160801b02600160801b600160c01b0319909316929092178255670de0b6b3a764000060019092018290556004805490919061134290849061254b565b9091555050604051670de0b6b3a7640000815233907fb539ca1e5c8d398ddf1c41c30166f33404941683be4683319b57669a93dad4ef906020015b60405180910390a2565b61139033611b9e565b33600090815260066020526040812060010181905560048054670de0b6b3a764000092906113bf90849061251f565b9091555050604051670de0b6b3a7640000815233907f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b9060200161137d565b600080805461140c906124c5565b80601f0160208091040260200160405190810160405280929190818152602001828054611438906124c5565b80156114855780601f1061145a57610100808354040283529160200191611485565b820191906000526020600020905b81548152906001019060200180831161146857829003601f168201915b50505050509050816000908161149b91906125ae565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051610bf992919061266d565b60606114f2838360405180606001604052806027815260200161281460279139611c6d565b9392505050565b6001600160a01b038116600090815260066020526040812060010154810361153a57506001600160a01b031660009081526006602052604090206002015490565b611543826118b7565b6001600160a01b038316600090815260066020526040902060020154610aab919061254b565b611571610888565b6001600160a01b0316336001600160a01b0316146115a15760405162461bcd60e51b815260040161018c906123ac565b60085481116115bd57806008546115b8919061251f565b6115c0565b60005b6008556116107f00000000000000000000000000000000000000000000000000000000000000003033847f0000000000000000000000000000000000000000000000000000000000000000611762565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461167c577f000000000000000000000000000000000000000000000000000000000000000061169e565b7f00000000000000000000000000000000000000000000000000000000000000005b9050600454816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116cf919061216e565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117109190612532565b101561175e5760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e6720746f6b656e2062616c616e636520726564756365642e0000604482015260640161018c565b5050565b81156118b05773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038616016118a457306001600160a01b0385160361180757604051632e1a7d4d60e01b8152600481018390526001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b1580156117df57600080fd5b505af11580156117f3573d6000803e3d6000fd5b50505050611802838383611ce5565b6118b0565b306001600160a01b0384160361189957348214611840576040516303e085f960e01b81523460048201526024810183905260440161018c565b806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561187b57600080fd5b505af115801561188f573d6000803e3d6000fd5b50505050506118b0565b611802838383611ce5565b6118b085858585611daa565b5050505050565b6001600160a01b0381166000908152600660209081526040808320815160808101835281546001600160801b03811682526001600160401b03600160801b9091048116948201859052600183015493820193909352600290910154606082015260035490929116815b81811015611a75576000818152600760209081526040808320815160a08101835281546001600160501b038082168352600160501b8204811695830195909552600160a01b90049093169183019190915260018101546060830152600201546080820152908483036119935785516119a2565b81602001516001600160501b03165b6001600160801b03169050600082604001516001600160501b03166000036119ca57426119d9565b82604001516001600160501b03165b9050600080611a06896040015185856119f2919061251f565b6119fc9190612692565b8660600151611e02565b91509150600080611a3e8c886080015189600001516001600160501b031686611a2f91906126bf565b611a3991906126bf565b611e4d565b91509150838015611a4c5750815b611a56578b611a58565b805b9b5050505050505050600181611a6e919061254b565b9050611920565b50611aaa84611aa57f0000000000000000000000000000000000000000000000000000000000000000600a6127c5565b611e02565b9450611ad990507f0000000000000000000000000000000000000000000000000000000000000000600a6127c5565b611ae390856126bf565b95945050505050565b600854811115611b395760405162461bcd60e51b81526020600482015260186024820152774e6f7420656e6f7567682072657761726420746f6b656e7360401b604482015260640161018c565b8060086000828254611b4b919061251f565b9091555061175e90507f00000000000000000000000000000000000000000000000000000000000000003084847f0000000000000000000000000000000000000000000000000000000000000000611762565b6000611ba9826118b7565b6001600160a01b038316600090815260066020526040812060020180549293508392909190611bd990849061254b565b90915550506001600160a01b038216600090815260066020526040902080546001600160801b0319166001600160501b034216179055600354611c27906001906001600160401b03166123ea565b6001600160a01b03909216600090815260066020526040902080546001600160401b0393909316600160801b02600160801b600160c01b03199093169290921790915550565b6060600080856001600160a01b031685604051611c8a91906127d5565b600060405180830381855af49150503d8060008114611cc5576040519150601f19603f3d011682016040523d82523d6000602084013e611cca565b606091505b5091509150611cdb86838387611e68565b9695505050505050565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114611d32576040519150601f19603f3d011682016040523d82523d6000602084013e611d37565b606091505b5050905080610f0a57816001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d7b57600080fd5b505af1158015611d8f573d6000803e3d6000fd5b50610f0a935050506001600160a01b03841690508585611ee9565b816001600160a01b0316836001600160a01b03160315610f0a57306001600160a01b03841603611ded57611de86001600160a01b0385168383611ee9565b610f0a565b610f0a6001600160a01b038516848484611f51565b60008083600003611e195750600190506000611e46565b83830283858281611e2c57611e2c6126a9565b0414611e3f576000809250925050611e46565b6001925090505b9250929050565b60008083830184811015611e3f576000809250925050611e46565b60608315611ed7578251600003611ed0576001600160a01b0385163b611ed05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161018c565b5081611ee1565b611ee18383611f89565b949350505050565b6040516001600160a01b038316602482015260448101829052611f4c90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611fb3565b505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610f0a9085906323b872dd60e01b90608401611f15565b815115611f995781518083602001fd5b8060405162461bcd60e51b815260040161018c9190612399565b6000612008826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166120859092919063ffffffff16565b805190915015611f4c578080602001905181019061202691906127f1565b611f4c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161018c565b6060611ee1848460008585600080866001600160a01b031685876040516120ac91906127d5565b60006040518083038185875af1925050503d80600081146120e9576040519150601f19603f3d011682016040523d82523d6000602084013e6120ee565b606091505b50915091506120ff87838387611e68565b979650505050505050565b6000806040838503121561211d57600080fd5b50508035926020909101359150565b60006020828403121561213e57600080fd5b81356001600160a01b03811681146114f257600080fd5b60006020828403121561216757600080fd5b5035919050565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156121aa57600080fd5b81356001600160401b03808211156121c157600080fd5b818401915084601f8301126121d557600080fd5b8135818111156121e7576121e7612182565b604051601f8201601f19908116603f0116810190838211818310171561220f5761220f612182565b8160405282815287602084870101111561222857600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000806020838503121561225b57600080fd5b82356001600160401b038082111561227257600080fd5b818501915085601f83011261228657600080fd5b81358181111561229557600080fd5b8660208260051b85010111156122aa57600080fd5b60209290920196919550909350505050565b60005b838110156122d75781810151838201526020016122bf565b50506000910152565b600081518084526122f88160208601602086016122bc565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561236357603f198886030184526123518583516122e0565b94509285019290850190600101612335565b5092979650505050505050565b60006020828403121561238257600080fd5b81356001600160501b03811681146114f257600080fd5b6020815260006114f260208301846122e0565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b0382811682821603908082111561240a5761240a6123d4565b5092915050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261247557600080fd5b8301803591506001600160401b0382111561248f57600080fd5b602001915036819003821315611e4657600080fd5b8284823760609190911b6001600160601b0319169101908152601401919050565b600181811c908216806124d957607f821691505b6020821081036124f957634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160401b0381811683821601908082111561240a5761240a6123d4565b81810381811115610aab57610aab6123d4565b60006020828403121561254457600080fd5b5051919050565b80820180821115610aab57610aab6123d4565b601f821115611f4c576000816000526020600020601f850160051c810160208610156125875750805b601f850160051c820191505b818110156125a657828155600101612593565b505050505050565b81516001600160401b038111156125c7576125c7612182565b6125db816125d584546124c5565b8461255e565b602080601f83116001811461261057600084156125f85750858301515b600019600386901b1c1916600185901b1785556125a6565b600085815260208120601f198616915b8281101561263f57888601518255948401946001909101908401612620565b508582101561265d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408152600061268060408301856122e0565b8281036020840152611ae381856122e0565b8082028115828204841417610aab57610aab6123d4565b634e487b7160e01b600052601260045260246000fd5b6000826126dc57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561271c578160001904821115612702576127026123d4565b8085161561270f57918102915b93841c93908002906126e6565b509250929050565b60008261273357506001610aab565b8161274057506000610aab565b816001811461275657600281146127605761277c565b6001915050610aab565b60ff841115612771576127716123d4565b50506001821b610aab565b5060208310610133831016604e8410600b841016171561279f575081810a610aab565b6127a983836126e1565b80600019048211156127bd576127bd6123d4565b029392505050565b60006114f261ffff841683612724565b600082516127e78184602087016122bc565b9190910192915050565b60006020828403121561280357600080fd5b815180151581146114f257600080fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122097099cb2b1d5e5462d2ed985c348aebf25c6dc2ec2040261da1ec5622de1e7ab64736f6c634300081700330000000000000000000000000000000000000000000000000000000000000001000000000000000000000000a3c2c8ce6be1c55401b5f1efb6112a86f6374429000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000021c0000000000000000000000000f7127c505ef9bb661da4e104b01dc9aee2bf4435000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b0000000000000000000000004200000000000000000000000000000000000006

Deployed Bytecode

0x6080604052600436106101135760003560e01c80621b79341461019c57806313af4035146101bc57806316c621e0146101dc578063372500ab146101ef5780633a4b66f1146102045780633ccfd60b1461021957806372f702f31461022e5780638caaa271146102785780638da5cb5b1461029c5780639168ae72146102b1578063938e3d7b1461033a57806393ce53431461035a57806397e1b4bc1461036f5780639bdcecd114610399578063ac9650d8146103e0578063b218f0691461040d578063b9f7a7b51461042d578063c345315314610461578063c93c8f3414610481578063cb43b2dd146104c1578063d68124c7146104e1578063e8a3d485146104f6578063f7c618c11461051857600080fd5b3661019757336001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616146101955760405162461bcd60e51b815260206004820181905260248201527f63616c6c6572206e6f74206e617469766520746f6b656e20777261707065722e60448201526064015b60405180910390fd5b005b600080fd5b3480156101a857600080fd5b506101956101b736600461210a565b61054c565b3480156101c857600080fd5b506101956101d736600461212c565b6106b6565b6101956101ea366004612155565b6106e7565b3480156101fb57600080fd5b5061019561071d565b34801561021057600080fd5b50610195610751565b34801561022557600080fd5b506101956107f1565b34801561023a57600080fd5b506102627f000000000000000000000000f7127c505ef9bb661da4e104b01dc9aee2bf443581565b60405161026f919061216e565b60405180910390f35b34801561028457600080fd5b5061028e60045481565b60405190815260200161026f565b3480156102a857600080fd5b50610262610888565b3480156102bd57600080fd5b506103086102cc36600461212c565b6006602052600090815260409020805460018201546002909201546001600160801b03821692600160801b9092046001600160401b0316919084565b604080516001600160801b0390951685526001600160401b03909316602085015291830152606082015260800161026f565b34801561034657600080fd5b50610195610355366004612198565b610897565b34801561036657600080fd5b5060085461028e565b34801561037b57600080fd5b506103846108c5565b6040805192835260208301919091520161026f565b3480156103a557600080fd5b506103cd7f000000000000000000000000000000000000000000000000000000000000001281565b60405161ffff909116815260200161026f565b3480156103ec57600080fd5b506104006103fb366004612248565b61094b565b60405161026f919061230c565b34801561041957600080fd5b50610195610428366004612370565b610ab1565b34801561043957600080fd5b506103cd7f000000000000000000000000000000000000000000000000000000000000001281565b34801561046d57600080fd5b5061038461047c36600461212c565b610c05565b34801561048d57600080fd5b506104b161049c36600461212c565b60056020526000908152604090205460ff1681565b604051901515815260200161026f565b3480156104cd57600080fd5b506101956104dc366004612155565b610c32565b3480156104ed57600080fd5b5061028e610c60565b34801561050257600080fd5b5061050b610ca8565b60405161026f9190612399565b34801561052457600080fd5b506102627f000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b81565b610554610d36565b6105705760405162461bcd60e51b815260040161018c906123ac565b6003546000906007908290610590906001906001600160401b03166123ea565b6001600160401b031681526020808201929092526040908101600020815160a08101835281546001600160501b038082168352600160501b8204811695830195909552600160a01b900490931691830191909152600181015460608301819052600290910154608083015290915083141580610610575080608001518214155b6106565760405162461bcd60e51b81526020600482015260176024820152762932bbb0b932103930ba34b7903ab731b430b733b2b21760491b604482015260640161018c565b8051610663908484610d59565b60608082015160808084015160408051938452602084018890528301529181018490527feb6684a1e7c9bd2adc792fb253558f022bcbef39fb6ad31dc58cdfefdd5b5190910160405180910390a1505050565b6106be610d36565b6106db576040516316ccb9cb60e11b815260040160405180910390fd5b6106e481610f10565b50565b60028054036107085760405162461bcd60e51b815260040161018c90612411565b6002805561071581610f62565b506001600255565b600280540361073e5760405162461bcd60e51b815260040161018c90612411565b6002805561074a611181565b6001600255565b60028054036107725760405162461bcd60e51b815260040161018c90612411565b600280553360009081526005602052604090205460ff16156107c75760405162461bcd60e51b815260206004820152600e60248201526d105b1c9958591e481cdd185ad95960921b604482015260640161018c565b6107cf6112a7565b336000908152600560205260409020805460ff19166001908117909155600255565b60028054036108125760405162461bcd60e51b815260040161018c90612411565b600280553360009081526005602052604090205460ff166108625760405162461bcd60e51b815260206004820152600a602482015269139bdd081cdd185ad95960b21b604482015260640161018c565b61086a611387565b336000908152600560205260409020805460ff191690556001600255565b6001546001600160a01b031690565b61089f610d36565b6108bc57604051639f7f092560e01b815260040160405180910390fd5b6106e4816113fe565b600354600090819060079082906108e7906001906001600160401b03166123ea565b6001600160401b03168152602001908152602001600020600101549150600760006001600360009054906101000a90046001600160401b031661092a91906123ea565b6001600160401b031681526020019081526020016000206002015490509091565b6060816001600160401b0381111561096557610965612182565b60405190808252806020026020018201604052801561099857816020015b60608152602001906001900390816109835790505b509050336000805b84811015610aa7578115610a1f576109fd308787848181106109c4576109c4612448565b90506020028101906109d6919061245e565b866040516020016109e9939291906124a4565b6040516020818303038152906040526114cd565b848281518110610a0f57610a0f612448565b6020026020010181905250610a9f565b610a8130878784818110610a3557610a35612448565b9050602002810190610a47919061245e565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506114cd92505050565b848281518110610a9357610a93612448565b60200260200101819052505b6001016109a0565b5050505b92915050565b610ab9610d36565b610ad55760405162461bcd60e51b815260040161018c906123ac565b6003546000906007908290610af5906001906001600160401b03166123ea565b6001600160401b031681526020808201929092526040908101600020815160a08101835281546001600160501b03808216808452600160501b8304821696840196909652600160a01b9091048116938201939093526001820154606082015260029091015460808201529250831603610ba75760405162461bcd60e51b81526020600482015260146024820152732a34b6b296bab734ba103ab731b430b733b2b21760611b604482015260640161018c565b610bba8282606001518360800151610d59565b8051604080516001600160501b03928316815291841660208301527fd968de290ed68f978b9e4816f7d4be9ef46189fe8eeb3eeb86199e7229cf2de091015b60405180910390a15050565b6001600160a01b03811660009081526006602052604081206001015490610c2b836114f9565b9050915091565b6002805403610c535760405162461bcd60e51b815260040161018c90612411565b6002805561071581611569565b6003546000906007908290610c80906001906001600160401b03166123ea565b6001600160401b031681526020810191909152604001600020546001600160501b0316919050565b60008054610cb5906124c5565b80601f0160208091040260200160405190810160405280929190818152602001828054610ce1906124c5565b8015610d2e5780601f10610d0357610100808354040283529160200191610d2e565b820191906000526020600020905b815481529060010190602001808311610d1157829003601f168201915b505050505081565b6000610d40610888565b6001600160a01b0316336001600160a01b031614905090565b80600003610d975760405162461bcd60e51b815260206004820152600b60248201526a064697669646520627920360ac1b604482015260640161018c565b826001600160501b0316600003610de75760405162461bcd60e51b8152602060048201526014602482015273074696d652d756e69742063616e277420626520360641b604482015260640161018c565b600380546001600160401b0316906001906000610e0483856124ff565b82546001600160401b039182166101009390930a9283029190920219909116179055506040805160a0810182526001600160501b03808716825242811660208084019182526000848601818152606086018a8152608087018a815289845260079094529690912094518554935191518516600160a01b02600160a01b600160f01b0319928616600160501b026001600160a01b0319909516919095161792909217919091169190911782559151600182015590516002909101558015610f0a574260076000610ed460018561251f565b815260200190815260200160002060000160146101000a8154816001600160501b0302191690836001600160501b031602179055505b50505050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7690600090a35050565b610f6a610888565b6001600160a01b0316336001600160a01b031614610f9a5760405162461bcd60e51b815260040161018c906123ac565b60007f000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b6001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14611006577f000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b611028565b7f00000000000000000000000042000000000000000000000000000000000000065b90506000816001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611058919061216e565b602060405180830381865afa158015611075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110999190612532565b90506110e87f000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b3330867f0000000000000000000000004200000000000000000000000000000000000006611762565b600081836001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611117919061216e565b602060405180830381865afa158015611134573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111589190612532565b611162919061251f565b90508060086000828254611176919061254b565b909155505050505050565b600061118c336118b7565b336000908152600660205260409020600201546111a9919061254b565b9050806000036111e85760405162461bcd60e51b815260206004820152600a6024820152694e6f207265776172647360b01b604482015260640161018c565b33600090815260066020526040812080546001600160801b031916426001600160501b03161781556002015560035461122c906001906001600160401b03166123ea565b33600081815260066020526040902080546001600160401b0393909316600160801b02600160801b600160c01b03199093169290921790915561126f9082611aec565b60405181815233907ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe9060200160405180910390a250565b33600090815260066020526040902080546001600160801b031916426001600160501b03161790556003546112e7906001906001600160401b03166123ea565b33600090815260066020526040812080546001600160401b0393909316600160801b02600160801b600160c01b0319909316929092178255670de0b6b3a764000060019092018290556004805490919061134290849061254b565b9091555050604051670de0b6b3a7640000815233907fb539ca1e5c8d398ddf1c41c30166f33404941683be4683319b57669a93dad4ef906020015b60405180910390a2565b61139033611b9e565b33600090815260066020526040812060010181905560048054670de0b6b3a764000092906113bf90849061251f565b9091555050604051670de0b6b3a7640000815233907f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b9060200161137d565b600080805461140c906124c5565b80601f0160208091040260200160405190810160405280929190818152602001828054611438906124c5565b80156114855780601f1061145a57610100808354040283529160200191611485565b820191906000526020600020905b81548152906001019060200180831161146857829003601f168201915b50505050509050816000908161149b91906125ae565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051610bf992919061266d565b60606114f2838360405180606001604052806027815260200161281460279139611c6d565b9392505050565b6001600160a01b038116600090815260066020526040812060010154810361153a57506001600160a01b031660009081526006602052604090206002015490565b611543826118b7565b6001600160a01b038316600090815260066020526040902060020154610aab919061254b565b611571610888565b6001600160a01b0316336001600160a01b0316146115a15760405162461bcd60e51b815260040161018c906123ac565b60085481116115bd57806008546115b8919061251f565b6115c0565b60005b6008556116107f000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b3033847f0000000000000000000000004200000000000000000000000000000000000006611762565b60007f000000000000000000000000f7127c505ef9bb661da4e104b01dc9aee2bf44356001600160a01b031673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461167c577f000000000000000000000000f7127c505ef9bb661da4e104b01dc9aee2bf443561169e565b7f00000000000000000000000042000000000000000000000000000000000000065b9050600454816001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016116cf919061216e565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117109190612532565b101561175e5760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e6720746f6b656e2062616c616e636520726564756365642e0000604482015260640161018c565b5050565b81156118b05773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeed196001600160a01b038616016118a457306001600160a01b0385160361180757604051632e1a7d4d60e01b8152600481018390526001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b1580156117df57600080fd5b505af11580156117f3573d6000803e3d6000fd5b50505050611802838383611ce5565b6118b0565b306001600160a01b0384160361189957348214611840576040516303e085f960e01b81523460048201526024810183905260440161018c565b806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561187b57600080fd5b505af115801561188f573d6000803e3d6000fd5b50505050506118b0565b611802838383611ce5565b6118b085858585611daa565b5050505050565b6001600160a01b0381166000908152600660209081526040808320815160808101835281546001600160801b03811682526001600160401b03600160801b9091048116948201859052600183015493820193909352600290910154606082015260035490929116815b81811015611a75576000818152600760209081526040808320815160a08101835281546001600160501b038082168352600160501b8204811695830195909552600160a01b90049093169183019190915260018101546060830152600201546080820152908483036119935785516119a2565b81602001516001600160501b03165b6001600160801b03169050600082604001516001600160501b03166000036119ca57426119d9565b82604001516001600160501b03165b9050600080611a06896040015185856119f2919061251f565b6119fc9190612692565b8660600151611e02565b91509150600080611a3e8c886080015189600001516001600160501b031686611a2f91906126bf565b611a3991906126bf565b611e4d565b91509150838015611a4c5750815b611a56578b611a58565b805b9b5050505050505050600181611a6e919061254b565b9050611920565b50611aaa84611aa57f0000000000000000000000000000000000000000000000000000000000000012600a6127c5565b611e02565b9450611ad990507f0000000000000000000000000000000000000000000000000000000000000012600a6127c5565b611ae390856126bf565b95945050505050565b600854811115611b395760405162461bcd60e51b81526020600482015260186024820152774e6f7420656e6f7567682072657761726420746f6b656e7360401b604482015260640161018c565b8060086000828254611b4b919061251f565b9091555061175e90507f000000000000000000000000ede54d9c024ee80c85ec0a75ed2d8774c7fbac9b3084847f0000000000000000000000004200000000000000000000000000000000000006611762565b6000611ba9826118b7565b6001600160a01b038316600090815260066020526040812060020180549293508392909190611bd990849061254b565b90915550506001600160a01b038216600090815260066020526040902080546001600160801b0319166001600160501b034216179055600354611c27906001906001600160401b03166123ea565b6001600160a01b03909216600090815260066020526040902080546001600160401b0393909316600160801b02600160801b600160c01b03199093169290921790915550565b6060600080856001600160a01b031685604051611c8a91906127d5565b600060405180830381855af49150503d8060008114611cc5576040519150601f19603f3d011682016040523d82523d6000602084013e611cca565b606091505b5091509150611cdb86838387611e68565b9695505050505050565b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114611d32576040519150601f19603f3d011682016040523d82523d6000602084013e611d37565b606091505b5050905080610f0a57816001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611d7b57600080fd5b505af1158015611d8f573d6000803e3d6000fd5b50610f0a935050506001600160a01b03841690508585611ee9565b816001600160a01b0316836001600160a01b03160315610f0a57306001600160a01b03841603611ded57611de86001600160a01b0385168383611ee9565b610f0a565b610f0a6001600160a01b038516848484611f51565b60008083600003611e195750600190506000611e46565b83830283858281611e2c57611e2c6126a9565b0414611e3f576000809250925050611e46565b6001925090505b9250929050565b60008083830184811015611e3f576000809250925050611e46565b60608315611ed7578251600003611ed0576001600160a01b0385163b611ed05760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161018c565b5081611ee1565b611ee18383611f89565b949350505050565b6040516001600160a01b038316602482015260448101829052611f4c90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611fb3565b505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610f0a9085906323b872dd60e01b90608401611f15565b815115611f995781518083602001fd5b8060405162461bcd60e51b815260040161018c9190612399565b6000612008826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166120859092919063ffffffff16565b805190915015611f4c578080602001905181019061202691906127f1565b611f4c5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161018c565b6060611ee1848460008585600080866001600160a01b031685876040516120ac91906127d5565b60006040518083038185875af1925050503d80600081146120e9576040519150601f19603f3d011682016040523d82523d6000602084013e6120ee565b606091505b50915091506120ff87838387611e68565b979650505050505050565b6000806040838503121561211d57600080fd5b50508035926020909101359150565b60006020828403121561213e57600080fd5b81356001600160a01b03811681146114f257600080fd5b60006020828403121561216757600080fd5b5035919050565b6001600160a01b0391909116815260200190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156121aa57600080fd5b81356001600160401b03808211156121c157600080fd5b818401915084601f8301126121d557600080fd5b8135818111156121e7576121e7612182565b604051601f8201601f19908116603f0116810190838211818310171561220f5761220f612182565b8160405282815287602084870101111561222857600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000806020838503121561225b57600080fd5b82356001600160401b038082111561227257600080fd5b818501915085601f83011261228657600080fd5b81358181111561229557600080fd5b8660208260051b85010111156122aa57600080fd5b60209290920196919550909350505050565b60005b838110156122d75781810151838201526020016122bf565b50506000910152565b600081518084526122f88160208601602086016122bc565b601f01601f19169290920160200192915050565b600060208083016020845280855180835260408601915060408160051b87010192506020870160005b8281101561236357603f198886030184526123518583516122e0565b94509285019290850190600101612335565b5092979650505050505050565b60006020828403121561238257600080fd5b81356001600160501b03811681146114f257600080fd5b6020815260006114f260208301846122e0565b6020808252600e908201526d139bdd08185d5d1a1bdc9a5e995960921b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b0382811682821603908082111561240a5761240a6123d4565b5092915050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261247557600080fd5b8301803591506001600160401b0382111561248f57600080fd5b602001915036819003821315611e4657600080fd5b8284823760609190911b6001600160601b0319169101908152601401919050565b600181811c908216806124d957607f821691505b6020821081036124f957634e487b7160e01b600052602260045260246000fd5b50919050565b6001600160401b0381811683821601908082111561240a5761240a6123d4565b81810381811115610aab57610aab6123d4565b60006020828403121561254457600080fd5b5051919050565b80820180821115610aab57610aab6123d4565b601f821115611f4c576000816000526020600020601f850160051c810160208610156125875750805b601f850160051c820191505b818110156125a657828155600101612593565b505050505050565b81516001600160401b038111156125c7576125c7612182565b6125db816125d584546124c5565b8461255e565b602080601f83116001811461261057600084156125f85750858301515b600019600386901b1c1916600185901b1785556125a6565b600085815260208120601f198616915b8281101561263f57888601518255948401946001909101908401612620565b508582101561265d5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60408152600061268060408301856122e0565b8281036020840152611ae381856122e0565b8082028115828204841417610aab57610aab6123d4565b634e487b7160e01b600052601260045260246000fd5b6000826126dc57634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561271c578160001904821115612702576127026123d4565b8085161561270f57918102915b93841c93908002906126e6565b509250929050565b60008261273357506001610aab565b8161274057506000610aab565b816001811461275657600281146127605761277c565b6001915050610aab565b60ff841115612771576127716123d4565b50506001821b610aab565b5060208310610133831016604e8410600b841016171561279f575081810a610aab565b6127a983836126e1565b80600019048211156127bd576127bd6123d4565b029392505050565b60006114f261ffff841683612724565b600082516127e78184602087016122bc565b9190910192915050565b60006020828403121561280357600080fd5b815180151581146114f257600080fdfe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a264697066735822122097099cb2b1d5e5462d2ed985c348aebf25c6dc2ec2040261da1ec5622de1e7ab64736f6c63430008170033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.