ETH Price: $3,091.32 (+0.08%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x67999bf63c33800f0d49b03da306a4210fd9889fbb34bc4b260af4134b7cc84f Claim Rewards(pending)2026-01-04 2:03:387 days ago1767492218IN
Cashmere: NFT Lock
0 ETH(Pending)(Pending)
Claim Rewards242098122026-01-11 6:56:1125 mins ago1768114571IN
Cashmere: NFT Lock
0 ETH0.000003060.04066719
Claim Rewards242097742026-01-11 6:48:3533 mins ago1768114115IN
Cashmere: NFT Lock
0 ETH0.00000250.03324006
Claim Rewards242097412026-01-11 6:41:5939 mins ago1768113719IN
Cashmere: NFT Lock
0 ETH0.000002920.03878969
Claim Rewards242097302026-01-11 6:39:4742 mins ago1768113587IN
Cashmere: NFT Lock
0 ETH0.000153282.0340959
Claim Rewards242094882026-01-11 5:50:591 hr ago1768110659IN
Cashmere: NFT Lock
0 ETH0.000002810.03732372
Claim Rewards242094232026-01-11 5:37:471 hr ago1768109867IN
Cashmere: NFT Lock
0 ETH0.000002420.03211711
Claim Rewards242093612026-01-11 5:25:231 hr ago1768109123IN
Cashmere: NFT Lock
0 ETH0.000003280.04353642
Claim Rewards242093492026-01-11 5:22:591 hr ago1768108979IN
Cashmere: NFT Lock
0 ETH0.00000240.03193517
Claim Rewards242093412026-01-11 5:21:232 hrs ago1768108883IN
Cashmere: NFT Lock
0 ETH0.000002480.03302831
Claim Rewards242091902026-01-11 4:51:112 hrs ago1768107071IN
Cashmere: NFT Lock
0 ETH0.000002440.03239166
Claim Rewards242091762026-01-11 4:48:112 hrs ago1768106891IN
Cashmere: NFT Lock
0 ETH0.000039890.52939632
Claim Rewards242089812026-01-11 4:08:593 hrs ago1768104539IN
Cashmere: NFT Lock
0 ETH0.000002410.03206872
Claim Rewards242088192026-01-11 3:36:353 hrs ago1768102595IN
Cashmere: NFT Lock
0 ETH0.000040130.53262489
Claim Rewards242087502026-01-11 3:22:473 hrs ago1768101767IN
Cashmere: NFT Lock
0 ETH0.000002420.03224137
Claim Rewards242086942026-01-11 3:11:234 hrs ago1768101083IN
Cashmere: NFT Lock
0 ETH0.00000230.03063791
Claim Rewards242086022026-01-11 2:52:594 hrs ago1768099979IN
Cashmere: NFT Lock
0 ETH0.000006180.08204268
Claim Rewards242085012026-01-11 2:32:474 hrs ago1768098767IN
Cashmere: NFT Lock
0 ETH0.000002350.03123326
Claim Rewards242084752026-01-11 2:27:354 hrs ago1768098455IN
Cashmere: NFT Lock
0 ETH0.000002130.02827774
Claim Rewards242083662026-01-11 2:05:475 hrs ago1768097147IN
Cashmere: NFT Lock
0 ETH0.000003710.04927949
Claim Rewards242083592026-01-11 2:04:235 hrs ago1768097063IN
Cashmere: NFT Lock
0 ETH0.000002680.03566512
Claim Rewards242079312026-01-11 0:37:476 hrs ago1768091867IN
Cashmere: NFT Lock
0 ETH0.000002520.03350269
Claim Rewards242079152026-01-11 0:34:356 hrs ago1768091675IN
Cashmere: NFT Lock
0 ETH0.000152932.02942063
Claim Rewards242078382026-01-11 0:19:117 hrs ago1768090751IN
Cashmere: NFT Lock
0 ETH0.000002290.03044129
Claim Rewards242075972026-01-10 23:30:597 hrs ago1768087859IN
Cashmere: NFT Lock
0 ETH0.000002460.03269685
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PermanentNFTStaking

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
No with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.11;

import "../lib/contracts/contracts/base/Staking721Base.sol";

/**
 * @title PermanentNFTStaking
 * @dev NFT staking contract where NFTs are permanently locked after staking.
 *      Users cannot withdraw their NFTs once staked, but the owner can perform emergency withdrawals.
 */
contract PermanentNFTStaking is Staking721Base {
    /// @dev Maximum NFTs that can be withdrawn in a single emergency batch
    uint256 public constant MAX_EMERGENCY_WITHDRAW_BATCH = 300;

    constructor(
        address _defaultAdmin,
        uint256 _timeUnit,
        uint256 _rewardsPerUnitTime,
        address _stakingToken,
        address _rewardToken,
        address _nativeTokenWrapper
    ) Staking721Base(
        _defaultAdmin,
        _timeUnit,
        _rewardsPerUnitTime,
        _stakingToken,
        _rewardToken,
        _nativeTokenWrapper
    ) {}

    /**
     * @dev Instead of overriding withdraw, we intercept the call in Staking721Base._withdraw
     */
    function _withdraw(uint256[] calldata) internal pure override {
        revert("NFTs are permanently staked");
    }
    
    /**
     * @dev Emergency withdraw function that can only be called by the owner
     * @param _tokenIds Array of token IDs to withdraw
     * @param _recipient Address to send the NFTs to
     */
    function emergencyWithdraw(uint256[] calldata _tokenIds, address _recipient) external nonReentrant {
        require(msg.sender == owner(), "Only owner can emergency withdraw");
        require(_recipient != address(0), "Cannot withdraw to zero address");
        require(_tokenIds.length <= MAX_EMERGENCY_WITHDRAW_BATCH, "Batch too large");
        
        address _stakingToken = stakingToken;
        
        for (uint256 i = 0; i < _tokenIds.length; i++) {
            // Check if the token is actually staked in this contract
            require(stakerAddress[_tokenIds[i]] != address(0), "Token not staked");
            
            // Clear staking data
            address staker = stakerAddress[_tokenIds[i]];
            stakerAddress[_tokenIds[i]] = address(0);
            
            // Update staker data
            if (stakers[staker].amountStaked > 0) {
                _updateUnclaimedRewardsForStaker(staker);
                stakers[staker].amountStaked -= 1;
                
                // Remove staker from array if no tokens left
                if (stakers[staker].amountStaked == 0) {
                    for (uint256 j = 0; j < stakersArray.length; j++) {
                        if (stakersArray[j] == staker) {
                            stakersArray[j] = stakersArray[stakersArray.length - 1];
                            stakersArray.pop();
                            break;
                        }
                    }
                }
            }
            
            // Transfer NFT to recipient
            IERC721(_stakingToken).safeTransferFrom(address(this), _recipient, _tokenIds[i]);
        }
        
        emit EmergencyWithdraw(msg.sender, _recipient, _tokenIds);
    }
    
    /**
     * @dev Event emitted when owner performs emergency withdrawal
     */
    event EmergencyWithdraw(address indexed owner, address indexed recipient, uint256[] tokenIds);
}

// 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/Staking721.sol";

import "../eip/ERC165.sol";
import "../eip/interface/IERC20.sol";
import "../eip/interface/IERC721Receiver.sol";

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

/**
 *
 *  EXTENSION: Staking721
 *
 *  The `Staking721Base` smart contract implements NFT staking mechanism.
 *  Allows users to stake their ERC-721 NFTs and earn rewards in form of ERC-20 tokens.
 *
 *  Following features and implementation setup must be noted:
 *
 *      - ERC-721 NFTs from only one NFT collection can be staked.
 *
 *      - Contract admin can choose to give out rewards by either transferring or minting the rewardToken,
 *        which is an ERC20 token. See {_mintRewards}.
 *
 *      - To implement custom logic for staking, reward calculation, etc. corresponding functions can be
 *        overridden from the extension `Staking721`.
 *
 *      - 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 Staking721Base is ContractMetadata, Multicall, Ownable, Staking721, ERC165, IERC721Receiver {
    /// @dev ERC20 Reward Token address. See {_mintRewards} below.
    address public immutable rewardToken;

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

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

    constructor(
        address _defaultAdmin,
        uint256 _timeUnit,
        uint256 _rewardsPerUnitTime,
        address _stakingToken,
        address _rewardToken,
        address _nativeTokenWrapper
    ) Staking721(_stakingToken) {
        _setupOwner(_defaultAdmin);
        _setStakingCondition(_timeUnit, _rewardsPerUnitTime);

        rewardToken = _rewardToken;
        nativeTokenWrapper = _nativeTokenWrapper;
    }

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

    /*///////////////////////////////////////////////////////////////
                        ERC 165 / 721 logic
    //////////////////////////////////////////////////////////////*/

    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external view virtual override returns (bytes4) {
        require(isStaking == 2, "Direct transfer");
        return this.onERC721Received.selector;
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC721Receiver).interfaceId || super.supportsInterface(interfaceId);
    }

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

    /// @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/IERC721.sol";

import "./interface/IStaking721.sol";

abstract contract Staking721 is ReentrancyGuard, IStaking721 {
    /*///////////////////////////////////////////////////////////////
                            State variables / Mappings
    //////////////////////////////////////////////////////////////*/

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

    /// @dev Flag to check direct transfers of staking tokens.
    uint8 internal isStaking = 1;

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

    ///@dev List of token-ids ever staked.
    uint256[] public indexedTokens;

    /// @dev List of accounts that have staked their NFTs.
    address[] public stakersArray;

    ///@dev Mapping from token-id to whether it is indexed or not.
    mapping(uint256 => bool) public isIndexed;

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

    /// @dev Mapping from staked token-id to staker address.
    mapping(uint256 => address) public stakerAddress;

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

    constructor(address _stakingToken) ReentrancyGuard() {
        require(address(_stakingToken) != address(0), "collection address 0");
        stakingToken = _stakingToken;
    }

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

    /**
     *  @notice    Stake ERC721 Tokens.
     *
     *  @dev       See {_stake}. Override that to implement custom logic.
     *
     *  @param _tokenIds    List of tokens to stake.
     */
    function stake(uint256[] calldata _tokenIds) external nonReentrant {
        _stake(_tokenIds);
    }

    /**
     *  @notice    Withdraw staked tokens.
     *
     *  @dev       See {_withdraw}. Override that to implement custom logic.
     *
     *  @param _tokenIds    List of tokens to withdraw.
     */
    function withdraw(uint256[] calldata _tokenIds) external nonReentrant {
        _withdraw(_tokenIds);
    }

    /**
     *  @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(uint256 _timeUnit) external virtual {
        if (!_canSetStakeConditions()) {
            revert("Not authorized");
        }

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

        _setStakingCondition(_timeUnit, condition.rewardsPerUnitTime);

        emit UpdatedTimeUnit(condition.timeUnit, _timeUnit);
    }

    /**
     *  @notice  Set rewards per unit of time.
     *           Interpreted as x rewards per second/per day/etc based on time-unit.
     *
     *  @dev     Only admin/authorized-account can call it.
     *
     *
     *  @param _rewardsPerUnitTime    New rewards per unit time.
     */
    function setRewardsPerUnitTime(uint256 _rewardsPerUnitTime) external virtual {
        if (!_canSetStakeConditions()) {
            revert("Not authorized");
        }

        StakingCondition memory condition = stakingConditions[nextConditionId - 1];
        require(_rewardsPerUnitTime != condition.rewardsPerUnitTime, "Reward unchanged.");

        _setStakingCondition(condition.timeUnit, _rewardsPerUnitTime);

        emit UpdatedRewardsPerUnitTime(condition.rewardsPerUnitTime, _rewardsPerUnitTime);
    }

    /**
     *  @notice View amount staked and total rewards for a user.
     *
     *  @param _staker          Address for which to calculated rewards.
     *  @return _tokensStaked   List of token-ids staked by staker.
     *  @return _rewards        Available reward amount.
     */
    function getStakeInfo(
        address _staker
    ) external view virtual returns (uint256[] memory _tokensStaked, uint256 _rewards) {
        uint256[] memory _indexedTokens = indexedTokens;
        bool[] memory _isStakerToken = new bool[](_indexedTokens.length);
        uint256 indexedTokenCount = _indexedTokens.length;
        uint256 stakerTokenCount = 0;

        for (uint256 i = 0; i < indexedTokenCount; i++) {
            _isStakerToken[i] = stakerAddress[_indexedTokens[i]] == _staker;
            if (_isStakerToken[i]) stakerTokenCount += 1;
        }

        _tokensStaked = new uint256[](stakerTokenCount);
        uint256 count = 0;
        for (uint256 i = 0; i < indexedTokenCount; i++) {
            if (_isStakerToken[i]) {
                _tokensStaked[count] = _indexedTokens[i];
                count += 1;
            }
        }

        _rewards = _availableRewards(_staker);
    }

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

    function getRewardsPerUnitTime() public view returns (uint256 _rewardsPerUnitTime) {
        _rewardsPerUnitTime = stakingConditions[nextConditionId - 1].rewardsPerUnitTime;
    }

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

    /// @dev Staking logic. Override to add custom logic.
    function _stake(uint256[] calldata _tokenIds) internal virtual {
        uint64 len = uint64(_tokenIds.length);
        require(len != 0, "Staking 0 tokens");

        address _stakingToken = stakingToken;

        if (stakers[_stakeMsgSender()].amountStaked > 0) {
            _updateUnclaimedRewardsForStaker(_stakeMsgSender());
        } else {
            stakersArray.push(_stakeMsgSender());
            stakers[_stakeMsgSender()].timeOfLastUpdate = uint128(block.timestamp);
            stakers[_stakeMsgSender()].conditionIdOflastUpdate = nextConditionId - 1;
        }
        for (uint256 i = 0; i < len; ++i) {
            isStaking = 2;
            IERC721(_stakingToken).safeTransferFrom(_stakeMsgSender(), address(this), _tokenIds[i]);
            isStaking = 1;

            stakerAddress[_tokenIds[i]] = _stakeMsgSender();

            if (!isIndexed[_tokenIds[i]]) {
                isIndexed[_tokenIds[i]] = true;
                indexedTokens.push(_tokenIds[i]);
            }
        }
        stakers[_stakeMsgSender()].amountStaked += len;

        emit TokensStaked(_stakeMsgSender(), _tokenIds);
    }

    /// @dev Withdraw logic. Override to add custom logic.
    function _withdraw(uint256[] calldata _tokenIds) internal virtual {
        uint256 _amountStaked = stakers[_stakeMsgSender()].amountStaked;
        uint64 len = uint64(_tokenIds.length);
        require(len != 0, "Withdrawing 0 tokens");
        require(_amountStaked >= len, "Withdrawing more than staked");

        address _stakingToken = stakingToken;

        _updateUnclaimedRewardsForStaker(_stakeMsgSender());

        if (_amountStaked == len) {
            address[] memory _stakersArray = stakersArray;
            for (uint256 i = 0; i < _stakersArray.length; ++i) {
                if (_stakersArray[i] == _stakeMsgSender()) {
                    stakersArray[i] = _stakersArray[_stakersArray.length - 1];
                    stakersArray.pop();
                    break;
                }
            }
        }
        stakers[_stakeMsgSender()].amountStaked -= len;

        for (uint256 i = 0; i < len; ++i) {
            require(stakerAddress[_tokenIds[i]] == _stakeMsgSender(), "Not staker");
            stakerAddress[_tokenIds[i]] = address(0);
            IERC721(_stakingToken).safeTransferFrom(address(this), _stakeMsgSender(), _tokenIds[i]);
        }

        emit TokensWithdrawn(_stakeMsgSender(), _tokenIds);
    }

    /// @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 = uint128(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 _user) internal view virtual returns (uint256 _rewards) {
        if (stakers[_user].amountStaked == 0) {
            _rewards = stakers[_user].unclaimedRewards;
        } else {
            _rewards = stakers[_user].unclaimedRewards + _calculateRewards(_user);
        }
    }

    /// @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 = uint128(block.timestamp);
        stakers[_staker].conditionIdOflastUpdate = nextConditionId - 1;
    }

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

        stakingConditions[conditionId] = StakingCondition({
            timeUnit: _timeUnit,
            rewardsPerUnitTime: _rewardsPerUnitTime,
            startTimestamp: block.timestamp,
            endTimestamp: 0
        });

        if (conditionId > 0) {
            stakingConditions[conditionId - 1].endTimestamp = 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.rewardsPerUnitTime
            );
            (bool noOverflowSum, uint256 rewardsSum) = SafeMath.tryAdd(_rewards, rewardsProduct / condition.timeUnit);

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

    /*////////////////////////////////////////////////////////////////////
        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: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./interface/IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

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

File 9 of 21 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// 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 15 of 21 : 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: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

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

/// @author thirdweb

interface IStaking721 {
    /// @dev Emitted when a set of token-ids are staked.
    event TokensStaked(address indexed staker, uint256[] indexed tokenIds);

    /// @dev Emitted when a set of staked token-ids are withdrawn.
    event TokensWithdrawn(address indexed staker, uint256[] indexed tokenIds);

    /// @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 UpdatedRewardsPerUnitTime(uint256 oldRewardsPerUnitTime, uint256 newRewardsPerUnitTime);

    /**
     *  @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 {
        uint64 amountStaked;
        uint64 conditionIdOflastUpdate;
        uint128 timeOfLastUpdate;
        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 rewardsPerUnitTime Rewards accumulated per unit of time.
     *
     *  @param startTimestamp     Condition start timestamp.
     *
     *  @param endTimestamp       Condition end timestamp.
     */
    struct StakingCondition {
        uint256 timeUnit;
        uint256 rewardsPerUnitTime;
        uint256 startTimestamp;
        uint256 endTimestamp;
    }

    /**
     *  @notice Stake ERC721 Tokens.
     *
     *  @param tokenIds    List of tokens to stake.
     */
    function stake(uint256[] calldata tokenIds) external;

    /**
     *  @notice Withdraw staked tokens.
     *
     *  @param tokenIds    List of tokens to withdraw.
     */
    function withdraw(uint256[] calldata tokenIds) 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[] memory _tokensStaked, uint256 _rewards);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * [EIP](https://eips.ethereum.org/EIPS/eip-165).
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// 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": [
    "@chainlink/=lib/contracts/lib/chainlink/",
    "@ds-test/=lib/contracts/lib/ds-test/src/",
    "@openzeppelin/contracts-upgradeable/=lib/contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/contracts/lib/openzeppelin-contracts/contracts/",
    "@rari-capital/solmate/=lib/contracts/lib/seaport/lib/solmate/",
    "@seaport/=lib/contracts/lib/seaport/contracts/",
    "@solady/=lib/contracts/lib/solady/",
    "@std/=lib/contracts/lib/forge-std/src/",
    "@thirdweb-dev/dynamic-contracts/=lib/contracts/lib/dynamic-contracts/",
    "ERC721A-Upgradeable/=lib/contracts/lib/ERC721A-Upgradeable/contracts/",
    "ERC721A/=lib/contracts/lib/ERC721A/contracts/",
    "chainlink/=lib/contracts/lib/chainlink/contracts/",
    "contracts/=lib/contracts/contracts/",
    "ds-test/=lib/contracts/lib/ds-test/src/",
    "dynamic-contracts/=lib/contracts/lib/dynamic-contracts/src/",
    "erc4626-tests/=lib/contracts/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "erc721a-upgradeable/=lib/contracts/lib/ERC721A-Upgradeable/",
    "erc721a/=lib/contracts/lib/ERC721A/",
    "forge-std/=lib/contracts/lib/forge-std/src/",
    "lib/sstore2/=lib/contracts/lib/dynamic-contracts/lib/sstore2/",
    "murky/=lib/contracts/lib/murky/src/",
    "openzeppelin-contracts-upgradeable/=lib/contracts/lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/contracts/lib/openzeppelin-contracts/",
    "openzeppelin/=lib/contracts/lib/openzeppelin-contracts-upgradeable/contracts/",
    "seaport-core/=lib/contracts/lib/seaport-core/src/",
    "seaport-sol/=lib/contracts/lib/seaport-sol/src/",
    "seaport-types/=lib/contracts/lib/seaport-types/src/",
    "seaport/=lib/contracts/lib/seaport/",
    "solady/=lib/contracts/lib/solady/src/",
    "solarray/=lib/contracts/lib/seaport/lib/solarray/src/",
    "solmate/=lib/contracts/lib/seaport/lib/solmate/src/",
    "sstore2/=lib/contracts/lib/dynamic-contracts/lib/sstore2/contracts/"
  ],
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_defaultAdmin","type":"address"},{"internalType":"uint256","name":"_timeUnit","type":"uint256"},{"internalType":"uint256","name":"_rewardsPerUnitTime","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":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"EmergencyWithdraw","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":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"TokensStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"TokensWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRewardsPerUnitTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRewardsPerUnitTime","type":"uint256"}],"name":"UpdatedRewardsPerUnitTime","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":"MAX_EMERGENCY_WITHDRAW_BATCH","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"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":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getRewardTokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardsPerUnitTime","outputs":[{"internalType":"uint256","name":"_rewardsPerUnitTime","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":"uint256","name":"","type":"uint256"}],"name":"indexedTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isIndexed","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":"nativeTokenWrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","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":[{"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":"_rewardsPerUnitTime","type":"uint256"}],"name":"setRewardsPerUnitTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_timeUnit","type":"uint256"}],"name":"setTimeUnit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakers","outputs":[{"internalType":"uint64","name":"amountStaked","type":"uint64"},{"internalType":"uint64","name":"conditionIdOflastUpdate","type":"uint64"},{"internalType":"uint128","name":"timeOfLastUpdate","type":"uint128"},{"internalType":"uint256","name":"unclaimedRewards","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakersArray","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"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"}]

60e0604052600160035f6101000a81548160ff021916908360ff16021790555034801561002a575f5ffd5b506040516159a43803806159a4833981810160405281019061004c919061042a565b8585858585858260016002819055505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036100c9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100c09061050d565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250505061010d8661019660201b60201c565b61011d858561025960201b60201c565b8173ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1681525050505050505050505050505050610641565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a35050565b5f820361029b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161029290610575565b60405180910390fd5b5f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690506001600360018282829054906101000a900467ffffffffffffffff166102e591906105d3565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405180608001604052808481526020018381526020014281526020015f81525060095f8381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301559050505f811115610394574260095f60018461037f919061060e565b81526020019081526020015f20600301819055505b505050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103c68261039d565b9050919050565b6103d6816103bc565b81146103e0575f5ffd5b50565b5f815190506103f1816103cd565b92915050565b5f819050919050565b610409816103f7565b8114610413575f5ffd5b50565b5f8151905061042481610400565b92915050565b5f5f5f5f5f5f60c0878903121561044457610443610399565b5b5f61045189828a016103e3565b965050602061046289828a01610416565b955050604061047389828a01610416565b945050606061048489828a016103e3565b935050608061049589828a016103e3565b92505060a06104a689828a016103e3565b9150509295509295509295565b5f82825260208201905092915050565b7f636f6c6c656374696f6e206164647265737320300000000000000000000000005f82015250565b5f6104f76014836104b3565b9150610502826104c3565b602082019050919050565b5f6020820190508181035f830152610524816104eb565b9050919050565b7f74696d652d756e69742063616e277420626520300000000000000000000000005f82015250565b5f61055f6014836104b3565b915061056a8261052b565b602082019050919050565b5f6020820190508181035f83015261058c81610553565b9050919050565b5f67ffffffffffffffff82169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6105dd82610593565b91506105e883610593565b9250828201905067ffffffffffffffff811115610608576106076105a6565b5b92915050565b5f610618826103f7565b9150610623836103f7565b925082820390508181111561063b5761063a6105a6565b5b92915050565b60805160a05160c0516152e56106bf5f395f81816101c101528181611b0d01528181612329015281816123ef01528181612d4b015261325901525f8181611ae9015281816122c701528181612303015281816123cb01528181612d27015261323501525f8181610e41015281816113be0152611c0b01526152e55ff3fe6080604052600436106101ba575f3560e01c80639168ae72116100eb578063c345315311610089578063e8a3d48511610063578063e8a3d485146106a5578063f7c618c1146106cf578063f9ea29cb146106f9578063fd48ba17146107235761024f565b8063c345315314610616578063cb43b2dd14610653578063d68124c71461067b5761024f565b806394067045116100c5578063940670451461053a578063961004d314610576578063983d95ce146105b2578063ac9650d8146105da5761024f565b80639168ae72146104a9578063938e3d7b146104e857806393ce5343146105105761024f565b806323ef2580116101585780636360106f116101325780636360106f146104055780636c60d9e71461042d57806372f702f3146104555780638da5cb5b1461047f5761024f565b806323ef25801461038b578063372500ab146103b35780635357e916146103c95761024f565b80630fbf0a93116101945780630fbf0a93146102e357806313af40351461030b578063150b7a021461033357806316c621e01461036f5761024f565b806301ffc9a714610253578063080cd2791461028f5780630e8b229b146102b95761024f565b3661024f577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461024d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024490613938565b60405180910390fd5b005b5f5ffd5b34801561025e575f5ffd5b50610279600480360381019061027491906139bc565b61075f565b6040516102869190613a01565b60405180910390f35b34801561029a575f5ffd5b506102a36107d8565b6040516102b09190613a32565b60405180910390f35b3480156102c4575f5ffd5b506102cd6107de565b6040516102da9190613a32565b60405180910390f35b3480156102ee575f5ffd5b5061030960048036038101906103049190613aac565b610825565b005b348015610316575f5ffd5b50610331600480360381019061032c9190613b51565b610886565b005b34801561033e575f5ffd5b5061035960048036038101906103549190613bfb565b6108d0565b6040516103669190613c8e565b60405180910390f35b61038960048036038101906103849190613ca7565b610938565b005b348015610396575f5ffd5b506103b160048036038101906103ac9190613ca7565b610997565b005b3480156103be575f5ffd5b506103c7610ae4565b005b3480156103d4575f5ffd5b506103ef60048036038101906103ea9190613ca7565b610b41565b6040516103fc9190613ce1565b60405180910390f35b348015610410575f5ffd5b5061042b60048036038101906104269190613ca7565b610b7c565b005b348015610438575f5ffd5b50610453600480360381019061044e9190613cfa565b610cc8565b005b348015610460575f5ffd5b506104696113bc565b6040516104769190613ce1565b60405180910390f35b34801561048a575f5ffd5b506104936113e0565b6040516104a09190613ce1565b60405180910390f35b3480156104b4575f5ffd5b506104cf60048036038101906104ca9190613b51565b611408565b6040516104df9493929190613da3565b60405180910390f35b3480156104f3575f5ffd5b5061050e60048036038101906105099190613f1e565b611475565b005b34801561051b575f5ffd5b506105246114bf565b6040516105319190613a32565b60405180910390f35b348015610545575f5ffd5b50610560600480360381019061055b9190613ca7565b6114c8565b60405161056d9190613ce1565b60405180910390f35b348015610581575f5ffd5b5061059c60048036038101906105979190613ca7565b6114f8565b6040516105a99190613a32565b60405180910390f35b3480156105bd575f5ffd5b506105d860048036038101906105d39190613aac565b611518565b005b3480156105e5575f5ffd5b5061060060048036038101906105fb9190613fba565b611579565b60405161060d9190614120565b60405180910390f35b348015610621575f5ffd5b5061063c60048036038101906106379190613b51565b61173a565b60405161064a9291906141f7565b60405180910390f35b34801561065e575f5ffd5b5061067960048036038101906106749190613ca7565b6119b7565b005b348015610686575f5ffd5b5061068f611a16565b60405161069c9190613a32565b60405180910390f35b3480156106b0575f5ffd5b506106b9611a5c565b6040516106c69190614267565b60405180910390f35b3480156106da575f5ffd5b506106e3611ae7565b6040516106f09190613ce1565b60405180910390f35b348015610704575f5ffd5b5061070d611b0b565b60405161071a9190613ce1565b60405180910390f35b34801561072e575f5ffd5b5061074960048036038101906107449190613ca7565b611b2f565b6040516107569190613a01565b60405180910390f35b5f7f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d157506107d082611b4c565b5b9050919050565b61012c81565b5f60095f6001600360019054906101000a900467ffffffffffffffff1661080591906142b4565b67ffffffffffffffff1681526020019081526020015f2060010154905090565b6002805403610869576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086090614339565b60405180910390fd5b6002808190555061087a8282611bb5565b60016002819055505050565b61088e612125565b6108c4576040517f2d99739600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108cd81612161565b50565b5f600260035f9054906101000a900460ff1660ff1614610925576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091c906143a1565b60405180910390fd5b63150b7a0260e01b905095945050505050565b600280540361097c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097390614339565b60405180910390fd5b6002808190555061098c81612224565b600160028190555050565b61099f6124b7565b6109de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d590614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610a0591906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015481526020016001820154815260200160028201548152602001600382015481525050905080602001518203610a96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8d90614471565b60405180910390fd5b610aa3815f0151836124f3565b7f243c4656edc72b2c7ec8575d464d955b2f42c1b205960c6c2fb7eecda5419cf6816020015183604051610ad892919061448f565b60405180910390a15050565b6002805403610b28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1f90614339565b60405180910390fd5b60028081905550610b37612633565b6001600281905550565b60058181548110610b50575f80fd5b905f5260205f20015f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610b846124b7565b610bc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bba90614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610bea91906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f820154815260200160018201548152602001600282015481526020016003820154815250509050805f01518203610c7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7190614500565b60405180910390fd5b610c888282602001516124f3565b7fd968de290ed68f978b9e4816f7d4be9ef46189fe8eeb3eeb86199e7229cf2de0815f015183604051610cbc92919061448f565b60405180910390a15050565b6002805403610d0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0390614339565b60405180910390fd5b60028081905550610d1b6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7f9061458e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610df6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ded906145f6565b60405180910390fd5b61012c838390501115610e3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e359061465e565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000090505f5f90505b84849050811015611346575f73ffffffffffffffffffffffffffffffffffffffff1660085f878785818110610e9f57610e9e61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603610f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f20906146f3565b60405180910390fd5b5f60085f878785818110610f4057610f3f61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60085f888886818110610f8d57610f8c61467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1611156112b55761104b8161289b565b600160075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166110ad91906142b4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff16036112b4575f5f90505b6005805490508110156112b2578173ffffffffffffffffffffffffffffffffffffffff16600582815481106111735761117261467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036112a557600560016005805490506111ca9190614711565b815481106111db576111da61467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600582815481106112175761121661467c565b5b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600580548061126e5761126d614744565b5b600190038181905f5260205f20015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556112b2565b808060010191505061113b565b505b5b8273ffffffffffffffffffffffffffffffffffffffff166342842e0e30868989878181106112e6576112e561467c565b5b905060200201356040518463ffffffff1660e01b815260040161130b93929190614771565b5f604051808303815f87803b158015611322575f5ffd5b505af1158015611334573d5f5f3e3d5ffd5b50505050508080600101915050610e67565b508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f49e7e98dba11447f42e55b1d3976705fad5dfb9df072d68da019756796baf3ef86866040516113a692919061480e565b60405180910390a3506001600281905550505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6007602052805f5260405f205f91509050805f015f9054906101000a900467ffffffffffffffff1690805f0160089054906101000a900467ffffffffffffffff1690805f0160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010154905084565b61147d6129ff565b6114b3576040517f9f7f092500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114bc81612a3b565b50565b5f600a54905090565b6008602052805f5260405f205f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60048181548110611507575f80fd5b905f5260205f20015f915090505481565b600280540361155c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155390614339565b60405180910390fd5b6002808190555061156d8282612b12565b60016002819055505050565b60608282905067ffffffffffffffff81111561159857611597613dfa565b5b6040519080825280602002602001820160405280156115cb57816020015b60608152602001906001900390816115b65790505b5090505f6115d7612b4d565b90505f8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141590505f5f90505b8585905081101561173157811561169557611672308787848181106116395761163861467c565b5b905060200281019061164b919061483c565b8660405160200161165e93929190614911565b604051602081830303815290604052612b54565b8482815181106116855761168461467c565b5b6020026020010181905250611724565b611705308787848181106116ac576116ab61467c565b5b90506020028101906116be919061483c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612b54565b8482815181106117185761171761467c565b5b60200260200101819052505b8080600101915050611611565b50505092915050565b60605f5f600480548060200260200160405190810160405280929190818152602001828054801561178857602002820191905f5260205f20905b815481526020019060010190808311611774575b505050505090505f815167ffffffffffffffff8111156117ab576117aa613dfa565b5b6040519080825280602002602001820160405280156117d95781602001602082028036833780820191505090505b5090505f825190505f5f90505f5f90505b828110156118cd578773ffffffffffffffffffffffffffffffffffffffff1660085f87848151811061181f5761181e61467c565b5b602002602001015181526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161484828151811061187e5761187d61467c565b5b6020026020010190151590811515815250508381815181106118a3576118a261467c565b5b6020026020010151156118c0576001826118bd919061493a565b91505b80806001019150506117ea565b508067ffffffffffffffff8111156118e8576118e7613dfa565b5b6040519080825280602002602001820160405280156119165781602001602082028036833780820191505090505b5095505f5f90505f5f90505b838110156119a15784818151811061193d5761193c61467c565b5b6020026020010151156119945785818151811061195d5761195c61467c565b5b60200260200101518883815181106119785761197761467c565b5b602002602001018181525050600182611991919061493a565b91505b8080600101915050611922565b506119ab88612b81565b95505050505050915091565b60028054036119fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f290614339565b60405180910390fd5b60028081905550611a0b81612c89565b600160028190555050565b5f60095f6001600360019054906101000a900467ffffffffffffffff16611a3d91906142b4565b67ffffffffffffffff1681526020019081526020015f205f0154905090565b5f8054611a689061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054611a949061499a565b8015611adf5780601f10611ab657610100808354040283529160200191611adf565b820191905f5260205f20905b815481529060010190602001808311611ac257829003601f168201915b505050505081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6006602052805f5260405f205f915054906101000a900460ff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f8282905090505f8167ffffffffffffffff1603611c08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bff90614a14565b60405180910390fd5b5f7f000000000000000000000000000000000000000000000000000000000000000090505f60075f611c38612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff161115611cac57611ca7611ca2612d72565b61289b565b611e20565b6005611cb6612d72565b908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504260075f611d1f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff16611db391906142b4565b60075f611dbe612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b5f5f90505b8267ffffffffffffffff1681101561202e57600260035f6101000a81548160ff021916908360ff1602179055508173ffffffffffffffffffffffffffffffffffffffff166342842e0e611e76612d72565b30888886818110611e8a57611e8961467c565b5b905060200201356040518463ffffffff1660e01b8152600401611eaf93929190614771565b5f604051808303815f87803b158015611ec6575f5ffd5b505af1158015611ed8573d5f5f3e3d5ffd5b50505050600160035f6101000a81548160ff021916908360ff160217905550611eff612d72565b60085f878785818110611f1557611f1461467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060065f868684818110611f7c57611f7b61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900460ff1661202357600160065f878785818110611fb957611fb861467c565b5b9050602002013581526020019081526020015f205f6101000a81548160ff0219169083151502179055506004858583818110611ff857611ff761467c565b5b90506020020135908060018154018082558091505060019003905f5260205f20015f90919091909150555b806001019050611e25565b508160075f61203b612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166120979190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083836040516120cd929190614ad2565b60405180910390206120dd612d72565b73ffffffffffffffffffffffffffffffffffffffff167f540cd34f06460fd67aeca9d19e0a56cd3a7c1cde8dc2263f265b68b2ef3495d260405160405180910390a350505050565b5f61212e6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a35050565b61222c6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229090614409565b60405180910390fd5b5f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1614612327577f0000000000000000000000000000000000000000000000000000000000000000612349565b7f00000000000000000000000000000000000000000000000000000000000000005b90505f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123859190613ce1565b602060405180830381865afa1580156123a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c49190614afe565b90506124137f00000000000000000000000000000000000000000000000000000000000000003330867f0000000000000000000000000000000000000000000000000000000000000000612d79565b5f818373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161244e9190613ce1565b602060405180830381865afa158015612469573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061248d9190614afe565b6124979190614711565b905080600a5f8282546124aa919061493a565b9250508190555050505050565b5f6124c06113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f8203612535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252c90614b73565b60405180910390fd5b5f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690506001600360018282829054906101000a900467ffffffffffffffff1661257f9190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405180608001604052808481526020018381526020014281526020015f81525060095f8381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301559050505f81111561262e574260095f6001846126199190614711565b81526020019081526020015f20600301819055505b505050565b5f61264461263f612d72565b612f73565b60075f61264f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612696919061493a565b90505f81036126da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d190614bdb565b60405180910390fd5b4260075f6126e6612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505f60075f612763612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101819055506001600360019054906101000a900467ffffffffffffffff166127c691906142b4565b60075f6127d1612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555061284361283d612d72565b826131d3565b61284b612d72565b73ffffffffffffffffffffffffffffffffffffffff167ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe826040516128909190613a32565b60405180910390a250565b5f6128a582612f73565b90508060075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206001015f8282546128f6919061493a565b925050819055504260075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff1661299691906142b4565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b5f612a086113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f5f8054612a489061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a749061499a565b8015612abf5780601f10612a9657610100808354040283529160200191612abf565b820191905f5260205f20905b815481529060010190602001808311612aa257829003601f168201915b50505050509050815f9081612ad49190614d99565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051612b06929190614e68565b60405180910390a15050565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b4490614ee7565b60405180910390fd5b5f33905090565b6060612b79838360405180606001604052806027815260200161528960279139613281565b905092915050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1603612c2d5760075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101549050612c84565b612c3682612f73565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612c81919061493a565b90505b919050565b612c916113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612cfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cf590614409565b60405180910390fd5b600a548111612d1a5780600a54612d159190614711565b612d1c565b5f5b600a81905550612d6f7f00000000000000000000000000000000000000000000000000000000000000003033847f0000000000000000000000000000000000000000000000000000000000000000612d79565b50565b5f33905090565b5f820315612f6c5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612f5e573073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612e71578073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b8152600401612e349190613a32565b5f604051808303815f87803b158015612e4b575f5ffd5b505af1158015612e5d573d5f5f3e3d5ffd5b50505050612e6c838383613303565b612f59565b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612f4c57348214612eea5734826040517f03e085f9000000000000000000000000000000000000000000000000000000008152600401612ee192919061448f565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b158015612f30575f5ffd5b505af1158015612f42573d5f5f3e3d5ffd5b5050505050612f58565b612f57838383613303565b5b5b612f6b565b612f6a858585856133ff565b5b5b5050505050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160089054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200160018201548152505090505f816020015167ffffffffffffffff1690505f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690505f8290505b818110156131ca575f60095f8381526020019081526020015f206040518060800160405290815f8201548152602001600182015481526020016002820154815260200160038201548152505090505f8483036131205785604001516fffffffffffffffffffffffffffffffff16613126565b81604001515b90505f5f83606001510361313a5742613140565b82606001515b90505f5f613175895f015167ffffffffffffffff1685856131619190614711565b61316b9190614f05565b86602001516134cb565b915091505f5f6131938c885f01518561318e9190614f73565b613519565b915091508380156131a15750815b6131ab578b6131ad565b805b9b50505050505050506001816131c3919061493a565b90506130ae565b50505050919050565b600a54811115613218576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320f90614fed565b60405180910390fd5b80600a5f8282546132299190614711565b9250508190555061327d7f00000000000000000000000000000000000000000000000000000000000000003084847f0000000000000000000000000000000000000000000000000000000000000000612d79565b5050565b60605f5f8573ffffffffffffffffffffffffffffffffffffffff16856040516132aa919061503b565b5f60405180830381855af49150503d805f81146132e2576040519150601f19603f3d011682016040523d82523d5f602084013e6132e7565b606091505b50915091506132f886838387613545565b925050509392505050565b5f8373ffffffffffffffffffffffffffffffffffffffff168360405161332890615074565b5f6040518083038185875af1925050503d805f8114613362576040519150601f19603f3d011682016040523d82523d5f602084013e613367565b606091505b50509050806133f9578173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b1580156133b6575f5ffd5b505af11580156133c8573d5f5f3e3d5ffd5b50505050506133f884848473ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b5b50505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603156134c5573073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036134965761349182828673ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b6134c4565b6134c38383838773ffffffffffffffffffffffffffffffffffffffff1661363f909392919063ffffffff16565b5b5b50505050565b5f5f5f84036134e05760015f91509150613512565b5f8385029050838582816134f7576134f6614f46565b5b0414613509575f5f9250925050613512565b60018192509250505b9250929050565b5f5f5f838501905084811015613535575f5f925092505061353e565b60018192509250505b9250929050565b606083156135a6575f83510361359e5761355e856136c8565b61359d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613594906150d2565b60405180910390fd5b5b8290506135b1565b6135b083836136ea565b5b949350505050565b61363a8363a9059cbb60e01b84846040516024016135d89291906150f0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b505050565b6136c2846323b872dd60e01b85858560405160240161366093929190614771565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b50505050565b5f5f8273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156136fc5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137309190614267565b60405180910390fd5b5f61379a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166137fe9092919063ffffffff16565b90505f815111156137f957808060200190518101906137b99190615141565b6137f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137ef906151dc565b60405180910390fd5b5b505050565b606061380c84845f85613815565b90509392505050565b60608247101561385a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016138519061526a565b60405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff168587604051613882919061503b565b5f6040518083038185875af1925050503d805f81146138bc576040519150601f19603f3d011682016040523d82523d5f602084013e6138c1565b606091505b50915091506138d287838387613545565b92505050949350505050565b5f82825260208201905092915050565b7f63616c6c6572206e6f74206e617469766520746f6b656e20777261707065722e5f82015250565b5f6139226020836138de565b915061392d826138ee565b602082019050919050565b5f6020820190508181035f83015261394f81613916565b9050919050565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61399b81613967565b81146139a5575f5ffd5b50565b5f813590506139b681613992565b92915050565b5f602082840312156139d1576139d061395f565b5b5f6139de848285016139a8565b91505092915050565b5f8115159050919050565b6139fb816139e7565b82525050565b5f602082019050613a145f8301846139f2565b92915050565b5f819050919050565b613a2c81613a1a565b82525050565b5f602082019050613a455f830184613a23565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836020820283011115613aa557613aa4613a53565b5b9250929050565b5f5f60208385031215613ac257613ac161395f565b5b5f83013567ffffffffffffffff811115613adf57613ade613963565b5b613aeb85828601613a57565b92509250509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613b2082613af7565b9050919050565b613b3081613b16565b8114613b3a575f5ffd5b50565b5f81359050613b4b81613b27565b92915050565b5f60208284031215613b6657613b6561395f565b5b5f613b7384828501613b3d565b91505092915050565b613b8581613a1a565b8114613b8f575f5ffd5b50565b5f81359050613ba081613b7c565b92915050565b5f5f83601f840112613bbb57613bba613a4b565b5b8235905067ffffffffffffffff811115613bd857613bd7613a4f565b5b602083019150836001820283011115613bf457613bf3613a53565b5b9250929050565b5f5f5f5f5f60808688031215613c1457613c1361395f565b5b5f613c2188828901613b3d565b9550506020613c3288828901613b3d565b9450506040613c4388828901613b92565b935050606086013567ffffffffffffffff811115613c6457613c63613963565b5b613c7088828901613ba6565b92509250509295509295909350565b613c8881613967565b82525050565b5f602082019050613ca15f830184613c7f565b92915050565b5f60208284031215613cbc57613cbb61395f565b5b5f613cc984828501613b92565b91505092915050565b613cdb81613b16565b82525050565b5f602082019050613cf45f830184613cd2565b92915050565b5f5f5f60408486031215613d1157613d1061395f565b5b5f84013567ffffffffffffffff811115613d2e57613d2d613963565b5b613d3a86828701613a57565b93509350506020613d4d86828701613b3d565b9150509250925092565b5f67ffffffffffffffff82169050919050565b613d7381613d57565b82525050565b5f6fffffffffffffffffffffffffffffffff82169050919050565b613d9d81613d79565b82525050565b5f608082019050613db65f830187613d6a565b613dc36020830186613d6a565b613dd06040830185613d94565b613ddd6060830184613a23565b95945050505050565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b613e3082613dea565b810181811067ffffffffffffffff82111715613e4f57613e4e613dfa565b5b80604052505050565b5f613e61613956565b9050613e6d8282613e27565b919050565b5f67ffffffffffffffff821115613e8c57613e8b613dfa565b5b613e9582613dea565b9050602081019050919050565b828183375f83830152505050565b5f613ec2613ebd84613e72565b613e58565b905082815260208101848484011115613ede57613edd613de6565b5b613ee9848285613ea2565b509392505050565b5f82601f830112613f0557613f04613a4b565b5b8135613f15848260208601613eb0565b91505092915050565b5f60208284031215613f3357613f3261395f565b5b5f82013567ffffffffffffffff811115613f5057613f4f613963565b5b613f5c84828501613ef1565b91505092915050565b5f5f83601f840112613f7a57613f79613a4b565b5b8235905067ffffffffffffffff811115613f9757613f96613a4f565b5b602083019150836020820283011115613fb357613fb2613a53565b5b9250929050565b5f5f60208385031215613fd057613fcf61395f565b5b5f83013567ffffffffffffffff811115613fed57613fec613963565b5b613ff985828601613f65565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6140608261402e565b61406a8185614038565b935061407a818560208601614048565b61408381613dea565b840191505092915050565b5f6140998383614056565b905092915050565b5f602082019050919050565b5f6140b782614005565b6140c1818561400f565b9350836020820285016140d38561401f565b805f5b8581101561410e57848403895281516140ef858261408e565b94506140fa836140a1565b925060208a019950506001810190506140d6565b50829750879550505050505092915050565b5f6020820190508181035f83015261413881846140ad565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61417281613a1a565b82525050565b5f6141838383614169565b60208301905092915050565b5f602082019050919050565b5f6141a582614140565b6141af818561414a565b93506141ba8361415a565b805f5b838110156141ea5781516141d18882614178565b97506141dc8361418f565b9250506001810190506141bd565b5085935050505092915050565b5f6040820190508181035f83015261420f818561419b565b905061421e6020830184613a23565b9392505050565b5f81519050919050565b5f61423982614225565b61424381856138de565b9350614253818560208601614048565b61425c81613dea565b840191505092915050565b5f6020820190508181035f83015261427f818461422f565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6142be82613d57565b91506142c983613d57565b9250828203905067ffffffffffffffff8111156142e9576142e8614287565b5b92915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c005f82015250565b5f614323601f836138de565b915061432e826142ef565b602082019050919050565b5f6020820190508181035f83015261435081614317565b9050919050565b7f446972656374207472616e7366657200000000000000000000000000000000005f82015250565b5f61438b600f836138de565b915061439682614357565b602082019050919050565b5f6020820190508181035f8301526143b88161437f565b9050919050565b7f4e6f7420617574686f72697a65640000000000000000000000000000000000005f82015250565b5f6143f3600e836138de565b91506143fe826143bf565b602082019050919050565b5f6020820190508181035f830152614420816143e7565b9050919050565b7f52657761726420756e6368616e6765642e0000000000000000000000000000005f82015250565b5f61445b6011836138de565b915061446682614427565b602082019050919050565b5f6020820190508181035f8301526144888161444f565b9050919050565b5f6040820190506144a25f830185613a23565b6144af6020830184613a23565b9392505050565b7f54696d652d756e697420756e6368616e6765642e0000000000000000000000005f82015250565b5f6144ea6014836138de565b91506144f5826144b6565b602082019050919050565b5f6020820190508181035f830152614517816144de565b9050919050565b7f4f6e6c79206f776e65722063616e20656d657267656e637920776974686472615f8201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b5f6145786021836138de565b91506145838261451e565b604082019050919050565b5f6020820190508181035f8301526145a58161456c565b9050919050565b7f43616e6e6f7420776974686472617720746f207a65726f2061646472657373005f82015250565b5f6145e0601f836138de565b91506145eb826145ac565b602082019050919050565b5f6020820190508181035f83015261460d816145d4565b9050919050565b7f426174636820746f6f206c6172676500000000000000000000000000000000005f82015250565b5f614648600f836138de565b915061465382614614565b602082019050919050565b5f6020820190508181035f8301526146758161463c565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f546f6b656e206e6f74207374616b6564000000000000000000000000000000005f82015250565b5f6146dd6010836138de565b91506146e8826146a9565b602082019050919050565b5f6020820190508181035f83015261470a816146d1565b9050919050565b5f61471b82613a1a565b915061472683613a1a565b925082820390508181111561473e5761473d614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f6060820190506147845f830186613cd2565b6147916020830185613cd2565b61479e6040830184613a23565b949350505050565b5f5ffd5b82818337505050565b5f6147be838561414a565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156147f1576147f06147a6565b5b6020830292506148028385846147aa565b82840190509392505050565b5f6020820190508181035f8301526148278184866147b3565b90509392505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f8335600160200384360303811261485857614857614830565b5b80840192508235915067ffffffffffffffff82111561487a57614879614834565b5b60208301925060018202360383131561489657614895614838565b5b509250929050565b5f81905092915050565b5f6148b3838561489e565b93506148c0838584613ea2565b82840190509392505050565b5f8160601b9050919050565b5f6148e2826148cc565b9050919050565b5f6148f3826148d8565b9050919050565b61490b61490682613b16565b6148e9565b82525050565b5f61491d8285876148a8565b915061492982846148fa565b601482019150819050949350505050565b5f61494482613a1a565b915061494f83613a1a565b925082820190508082111561496757614966614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806149b157607f821691505b6020821081036149c4576149c361496d565b5b50919050565b7f5374616b696e67203020746f6b656e73000000000000000000000000000000005f82015250565b5f6149fe6010836138de565b9150614a09826149ca565b602082019050919050565b5f6020820190508181035f830152614a2b816149f2565b9050919050565b5f614a3c82613d57565b9150614a4783613d57565b9250828201905067ffffffffffffffff811115614a6757614a66614287565b5b92915050565b5f81905092915050565b5f614a828385614a6d565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614ab557614ab46147a6565b5b602083029250614ac68385846147aa565b82840190509392505050565b5f614ade828486614a77565b91508190509392505050565b5f81519050614af881613b7c565b92915050565b5f60208284031215614b1357614b1261395f565b5b5f614b2084828501614aea565b91505092915050565b7f74696d652d756e69742063616e277420626520300000000000000000000000005f82015250565b5f614b5d6014836138de565b9150614b6882614b29565b602082019050919050565b5f6020820190508181035f830152614b8a81614b51565b9050919050565b7f4e6f2072657761726473000000000000000000000000000000000000000000005f82015250565b5f614bc5600a836138de565b9150614bd082614b91565b602082019050919050565b5f6020820190508181035f830152614bf281614bb9565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302614c557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614c1a565b614c5f8683614c1a565b95508019841693508086168417925050509392505050565b5f819050919050565b5f614c9a614c95614c9084613a1a565b614c77565b613a1a565b9050919050565b5f819050919050565b614cb383614c80565b614cc7614cbf82614ca1565b848454614c26565b825550505050565b5f5f905090565b614cde614ccf565b614ce9818484614caa565b505050565b5b81811015614d0c57614d015f82614cd6565b600181019050614cef565b5050565b601f821115614d5157614d2281614bf9565b614d2b84614c0b565b81016020851015614d3a578190505b614d4e614d4685614c0b565b830182614cee565b50505b505050565b5f82821c905092915050565b5f614d715f1984600802614d56565b1980831691505092915050565b5f614d898383614d62565b9150826002028217905092915050565b614da282614225565b67ffffffffffffffff811115614dbb57614dba613dfa565b5b614dc5825461499a565b614dd0828285614d10565b5f60209050601f831160018114614e01575f8415614def578287015190505b614df98582614d7e565b865550614e60565b601f198416614e0f86614bf9565b5f5b82811015614e3657848901518255600182019150602085019450602081019050614e11565b86831015614e535784890151614e4f601f891682614d62565b8355505b6001600288020188555050505b505050505050565b5f6040820190508181035f830152614e80818561422f565b90508181036020830152614e94818461422f565b90509392505050565b7f4e46547320617265207065726d616e656e746c79207374616b656400000000005f82015250565b5f614ed1601b836138de565b9150614edc82614e9d565b602082019050919050565b5f6020820190508181035f830152614efe81614ec5565b9050919050565b5f614f0f82613a1a565b9150614f1a83613a1a565b9250828202614f2881613a1a565b91508282048414831517614f3f57614f3e614287565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614f7d82613a1a565b9150614f8883613a1a565b925082614f9857614f97614f46565b5b828204905092915050565b7f4e6f7420656e6f7567682072657761726420746f6b656e7300000000000000005f82015250565b5f614fd76018836138de565b9150614fe282614fa3565b602082019050919050565b5f6020820190508181035f83015261500481614fcb565b9050919050565b5f6150158261402e565b61501f818561489e565b935061502f818560208601614048565b80840191505092915050565b5f615046828461500b565b915081905092915050565b50565b5f61505f5f8361489e565b915061506a82615051565b5f82019050919050565b5f61507e82615054565b9150819050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6150bc601d836138de565b91506150c782615088565b602082019050919050565b5f6020820190508181035f8301526150e9816150b0565b9050919050565b5f6040820190506151035f830185613cd2565b6151106020830184613a23565b9392505050565b615120816139e7565b811461512a575f5ffd5b50565b5f8151905061513b81615117565b92915050565b5f602082840312156151565761515561395f565b5b5f6151638482850161512d565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f6151c6602a836138de565b91506151d18261516c565b604082019050919050565b5f6020820190508181035f8301526151f3816151ba565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f6152546026836138de565b915061525f826151fa565b604082019050919050565b5f6020820190508181035f83015261528181615248565b905091905056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208d303b28d426b05eacbd0c12f762c5c0eb7ec880d79828074be3f892bfefaeb664736f6c634300081c0033000000000000000000000000fac9746e0b49d2d3982b43e754f0fe64b9883d270000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000aa87bee5380000000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

Deployed Bytecode

0x6080604052600436106101ba575f3560e01c80639168ae72116100eb578063c345315311610089578063e8a3d48511610063578063e8a3d485146106a5578063f7c618c1146106cf578063f9ea29cb146106f9578063fd48ba17146107235761024f565b8063c345315314610616578063cb43b2dd14610653578063d68124c71461067b5761024f565b806394067045116100c5578063940670451461053a578063961004d314610576578063983d95ce146105b2578063ac9650d8146105da5761024f565b80639168ae72146104a9578063938e3d7b146104e857806393ce5343146105105761024f565b806323ef2580116101585780636360106f116101325780636360106f146104055780636c60d9e71461042d57806372f702f3146104555780638da5cb5b1461047f5761024f565b806323ef25801461038b578063372500ab146103b35780635357e916146103c95761024f565b80630fbf0a93116101945780630fbf0a93146102e357806313af40351461030b578063150b7a021461033357806316c621e01461036f5761024f565b806301ffc9a714610253578063080cd2791461028f5780630e8b229b146102b95761024f565b3661024f577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461024d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161024490613938565b60405180910390fd5b005b5f5ffd5b34801561025e575f5ffd5b50610279600480360381019061027491906139bc565b61075f565b6040516102869190613a01565b60405180910390f35b34801561029a575f5ffd5b506102a36107d8565b6040516102b09190613a32565b60405180910390f35b3480156102c4575f5ffd5b506102cd6107de565b6040516102da9190613a32565b60405180910390f35b3480156102ee575f5ffd5b5061030960048036038101906103049190613aac565b610825565b005b348015610316575f5ffd5b50610331600480360381019061032c9190613b51565b610886565b005b34801561033e575f5ffd5b5061035960048036038101906103549190613bfb565b6108d0565b6040516103669190613c8e565b60405180910390f35b61038960048036038101906103849190613ca7565b610938565b005b348015610396575f5ffd5b506103b160048036038101906103ac9190613ca7565b610997565b005b3480156103be575f5ffd5b506103c7610ae4565b005b3480156103d4575f5ffd5b506103ef60048036038101906103ea9190613ca7565b610b41565b6040516103fc9190613ce1565b60405180910390f35b348015610410575f5ffd5b5061042b60048036038101906104269190613ca7565b610b7c565b005b348015610438575f5ffd5b50610453600480360381019061044e9190613cfa565b610cc8565b005b348015610460575f5ffd5b506104696113bc565b6040516104769190613ce1565b60405180910390f35b34801561048a575f5ffd5b506104936113e0565b6040516104a09190613ce1565b60405180910390f35b3480156104b4575f5ffd5b506104cf60048036038101906104ca9190613b51565b611408565b6040516104df9493929190613da3565b60405180910390f35b3480156104f3575f5ffd5b5061050e60048036038101906105099190613f1e565b611475565b005b34801561051b575f5ffd5b506105246114bf565b6040516105319190613a32565b60405180910390f35b348015610545575f5ffd5b50610560600480360381019061055b9190613ca7565b6114c8565b60405161056d9190613ce1565b60405180910390f35b348015610581575f5ffd5b5061059c60048036038101906105979190613ca7565b6114f8565b6040516105a99190613a32565b60405180910390f35b3480156105bd575f5ffd5b506105d860048036038101906105d39190613aac565b611518565b005b3480156105e5575f5ffd5b5061060060048036038101906105fb9190613fba565b611579565b60405161060d9190614120565b60405180910390f35b348015610621575f5ffd5b5061063c60048036038101906106379190613b51565b61173a565b60405161064a9291906141f7565b60405180910390f35b34801561065e575f5ffd5b5061067960048036038101906106749190613ca7565b6119b7565b005b348015610686575f5ffd5b5061068f611a16565b60405161069c9190613a32565b60405180910390f35b3480156106b0575f5ffd5b506106b9611a5c565b6040516106c69190614267565b60405180910390f35b3480156106da575f5ffd5b506106e3611ae7565b6040516106f09190613ce1565b60405180910390f35b348015610704575f5ffd5b5061070d611b0b565b60405161071a9190613ce1565b60405180910390f35b34801561072e575f5ffd5b5061074960048036038101906107449190613ca7565b611b2f565b6040516107569190613a01565b60405180910390f35b5f7f150b7a02000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806107d157506107d082611b4c565b5b9050919050565b61012c81565b5f60095f6001600360019054906101000a900467ffffffffffffffff1661080591906142b4565b67ffffffffffffffff1681526020019081526020015f2060010154905090565b6002805403610869576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161086090614339565b60405180910390fd5b6002808190555061087a8282611bb5565b60016002819055505050565b61088e612125565b6108c4576040517f2d99739600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108cd81612161565b50565b5f600260035f9054906101000a900460ff1660ff1614610925576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161091c906143a1565b60405180910390fd5b63150b7a0260e01b905095945050505050565b600280540361097c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161097390614339565b60405180910390fd5b6002808190555061098c81612224565b600160028190555050565b61099f6124b7565b6109de576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109d590614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610a0591906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015481526020016001820154815260200160028201548152602001600382015481525050905080602001518203610a96576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8d90614471565b60405180910390fd5b610aa3815f0151836124f3565b7f243c4656edc72b2c7ec8575d464d955b2f42c1b205960c6c2fb7eecda5419cf6816020015183604051610ad892919061448f565b60405180910390a15050565b6002805403610b28576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1f90614339565b60405180910390fd5b60028081905550610b37612633565b6001600281905550565b60058181548110610b50575f80fd5b905f5260205f20015f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610b846124b7565b610bc3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bba90614409565b60405180910390fd5b5f60095f6001600360019054906101000a900467ffffffffffffffff16610bea91906142b4565b67ffffffffffffffff1681526020019081526020015f206040518060800160405290815f820154815260200160018201548152602001600282015481526020016003820154815250509050805f01518203610c7a576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c7190614500565b60405180910390fd5b610c888282602001516124f3565b7fd968de290ed68f978b9e4816f7d4be9ef46189fe8eeb3eeb86199e7229cf2de0815f015183604051610cbc92919061448f565b60405180910390a15050565b6002805403610d0c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d0390614339565b60405180910390fd5b60028081905550610d1b6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610d88576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d7f9061458e565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610df6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ded906145f6565b60405180910390fd5b61012c838390501115610e3e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e359061465e565b60405180910390fd5b5f7f0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d90505f5f90505b84849050811015611346575f73ffffffffffffffffffffffffffffffffffffffff1660085f878785818110610e9f57610e9e61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603610f29576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f20906146f3565b60405180910390fd5b5f60085f878785818110610f4057610f3f61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f60085f888886818110610f8d57610f8c61467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1611156112b55761104b8161289b565b600160075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166110ad91906142b4565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505f60075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff16036112b4575f5f90505b6005805490508110156112b2578173ffffffffffffffffffffffffffffffffffffffff16600582815481106111735761117261467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16036112a557600560016005805490506111ca9190614711565b815481106111db576111da61467c565b5b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600582815481106112175761121661467c565b5b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600580548061126e5761126d614744565b5b600190038181905f5260205f20015f6101000a81549073ffffffffffffffffffffffffffffffffffffffff021916905590556112b2565b808060010191505061113b565b505b5b8273ffffffffffffffffffffffffffffffffffffffff166342842e0e30868989878181106112e6576112e561467c565b5b905060200201356040518463ffffffff1660e01b815260040161130b93929190614771565b5f604051808303815f87803b158015611322575f5ffd5b505af1158015611334573d5f5f3e3d5ffd5b50505050508080600101915050610e67565b508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f49e7e98dba11447f42e55b1d3976705fad5dfb9df072d68da019756796baf3ef86866040516113a692919061480e565b60405180910390a3506001600281905550505050565b7f0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d81565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6007602052805f5260405f205f91509050805f015f9054906101000a900467ffffffffffffffff1690805f0160089054906101000a900467ffffffffffffffff1690805f0160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010154905084565b61147d6129ff565b6114b3576040517f9f7f092500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6114bc81612a3b565b50565b5f600a54905090565b6008602052805f5260405f205f915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60048181548110611507575f80fd5b905f5260205f20015f915090505481565b600280540361155c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161155390614339565b60405180910390fd5b6002808190555061156d8282612b12565b60016002819055505050565b60608282905067ffffffffffffffff81111561159857611597613dfa565b5b6040519080825280602002602001820160405280156115cb57816020015b60608152602001906001900390816115b65790505b5090505f6115d7612b4d565b90505f8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141590505f5f90505b8585905081101561173157811561169557611672308787848181106116395761163861467c565b5b905060200281019061164b919061483c565b8660405160200161165e93929190614911565b604051602081830303815290604052612b54565b8482815181106116855761168461467c565b5b6020026020010181905250611724565b611705308787848181106116ac576116ab61467c565b5b90506020028101906116be919061483c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050612b54565b8482815181106117185761171761467c565b5b60200260200101819052505b8080600101915050611611565b50505092915050565b60605f5f600480548060200260200160405190810160405280929190818152602001828054801561178857602002820191905f5260205f20905b815481526020019060010190808311611774575b505050505090505f815167ffffffffffffffff8111156117ab576117aa613dfa565b5b6040519080825280602002602001820160405280156117d95781602001602082028036833780820191505090505b5090505f825190505f5f90505f5f90505b828110156118cd578773ffffffffffffffffffffffffffffffffffffffff1660085f87848151811061181f5761181e61467c565b5b602002602001015181526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161484828151811061187e5761187d61467c565b5b6020026020010190151590811515815250508381815181106118a3576118a261467c565b5b6020026020010151156118c0576001826118bd919061493a565b91505b80806001019150506117ea565b508067ffffffffffffffff8111156118e8576118e7613dfa565b5b6040519080825280602002602001820160405280156119165781602001602082028036833780820191505090505b5095505f5f90505f5f90505b838110156119a15784818151811061193d5761193c61467c565b5b6020026020010151156119945785818151811061195d5761195c61467c565b5b60200260200101518883815181106119785761197761467c565b5b602002602001018181525050600182611991919061493a565b91505b8080600101915050611922565b506119ab88612b81565b95505050505050915091565b60028054036119fb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119f290614339565b60405180910390fd5b60028081905550611a0b81612c89565b600160028190555050565b5f60095f6001600360019054906101000a900467ffffffffffffffff16611a3d91906142b4565b67ffffffffffffffff1681526020019081526020015f205f0154905090565b5f8054611a689061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054611a949061499a565b8015611adf5780601f10611ab657610100808354040283529160200191611adf565b820191905f5260205f20905b815481529060010190602001808311611ac257829003601f168201915b505050505081565b7f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f81565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6006602052805f5260405f205f915054906101000a900460ff1681565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b5f8282905090505f8167ffffffffffffffff1603611c08576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bff90614a14565b60405180910390fd5b5f7f0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d90505f60075f611c38612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff161115611cac57611ca7611ca2612d72565b61289b565b611e20565b6005611cb6612d72565b908060018154018082558091505060019003905f5260205f20015f9091909190916101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055504260075f611d1f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff16611db391906142b4565b60075f611dbe612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505b5f5f90505b8267ffffffffffffffff1681101561202e57600260035f6101000a81548160ff021916908360ff1602179055508173ffffffffffffffffffffffffffffffffffffffff166342842e0e611e76612d72565b30888886818110611e8a57611e8961467c565b5b905060200201356040518463ffffffff1660e01b8152600401611eaf93929190614771565b5f604051808303815f87803b158015611ec6575f5ffd5b505af1158015611ed8573d5f5f3e3d5ffd5b50505050600160035f6101000a81548160ff021916908360ff160217905550611eff612d72565b60085f878785818110611f1557611f1461467c565b5b9050602002013581526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060065f868684818110611f7c57611f7b61467c565b5b9050602002013581526020019081526020015f205f9054906101000a900460ff1661202357600160065f878785818110611fb957611fb861467c565b5b9050602002013581526020019081526020015f205f6101000a81548160ff0219169083151502179055506004858583818110611ff857611ff761467c565b5b90506020020135908060018154018082558091505060019003905f5260205f20015f90919091909150555b806001019050611e25565b508160075f61203b612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f8282829054906101000a900467ffffffffffffffff166120979190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555083836040516120cd929190614ad2565b60405180910390206120dd612d72565b73ffffffffffffffffffffffffffffffffffffffff167f540cd34f06460fd67aeca9d19e0a56cd3a7c1cde8dc2263f265b68b2ef3495d260405160405180910390a350505050565b5f61212e6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d7660405160405180910390a35050565b61222c6113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612299576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229090614409565b60405180910390fd5b5f73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f73ffffffffffffffffffffffffffffffffffffffff1614612327577f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f612349565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b90505f8173ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016123859190613ce1565b602060405180830381865afa1580156123a0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906123c49190614afe565b90506124137f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f3330867f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d79565b5f818373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b815260040161244e9190613ce1565b602060405180830381865afa158015612469573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061248d9190614afe565b6124979190614711565b905080600a5f8282546124aa919061493a565b9250508190555050505050565b5f6124c06113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f8203612535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161252c90614b73565b60405180910390fd5b5f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690506001600360018282829054906101000a900467ffffffffffffffff1661257f9190614a32565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405180608001604052808481526020018381526020014281526020015f81525060095f8381526020019081526020015f205f820151815f01556020820151816001015560408201518160020155606082015181600301559050505f81111561262e574260095f6001846126199190614711565b81526020019081526020015f20600301819055505b505050565b5f61264461263f612d72565b612f73565b60075f61264f612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612696919061493a565b90505f81036126da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126d190614bdb565b60405180910390fd5b4260075f6126e6612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055505f60075f612763612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101819055506001600360019054906101000a900467ffffffffffffffff166127c691906142b4565b60075f6127d1612d72565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555061284361283d612d72565b826131d3565b61284b612d72565b73ffffffffffffffffffffffffffffffffffffffff167ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe826040516128909190613a32565b60405180910390a250565b5f6128a582612f73565b90508060075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206001015f8282546128f6919061493a565b925050819055504260075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506001600360019054906101000a900467ffffffffffffffff1661299691906142b4565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f0160086101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055505050565b5f612a086113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905090565b5f5f8054612a489061499a565b80601f0160208091040260200160405190810160405280929190818152602001828054612a749061499a565b8015612abf5780601f10612a9657610100808354040283529160200191612abf565b820191905f5260205f20905b815481529060010190602001808311612aa257829003601f168201915b50505050509050815f9081612ad49190614d99565b507fc9c7c3fe08b88b4df9d4d47ef47d2c43d55c025a0ba88ca442580ed9e7348a168183604051612b06929190614e68565b60405180910390a15050565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612b4490614ee7565b60405180910390fd5b5f33905090565b6060612b79838360405180606001604052806027815260200161528960279139613281565b905092915050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1603612c2d5760075f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20600101549050612c84565b612c3682612f73565b60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2060010154612c81919061493a565b90505b919050565b612c916113e0565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612cfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612cf590614409565b60405180910390fd5b600a548111612d1a5780600a54612d159190614711565b612d1c565b5f5b600a81905550612d6f7f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f3033847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d79565b50565b5f33905090565b5f820315612f6c5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1603612f5e573073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603612e71578073ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d836040518263ffffffff1660e01b8152600401612e349190613a32565b5f604051808303815f87803b158015612e4b575f5ffd5b505af1158015612e5d573d5f5f3e3d5ffd5b50505050612e6c838383613303565b612f59565b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603612f4c57348214612eea5734826040517f03e085f9000000000000000000000000000000000000000000000000000000008152600401612ee192919061448f565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff1663d0e30db0836040518263ffffffff1660e01b81526004015f604051808303818588803b158015612f30575f5ffd5b505af1158015612f42573d5f5f3e3d5ffd5b5050505050612f58565b612f57838383613303565b5b5b612f6b565b612f6a858585856133ff565b5b5b5050505050565b5f5f60075f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f206040518060800160405290815f82015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160089054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16815260200160018201548152505090505f816020015167ffffffffffffffff1690505f600360019054906101000a900467ffffffffffffffff1667ffffffffffffffff1690505f8290505b818110156131ca575f60095f8381526020019081526020015f206040518060800160405290815f8201548152602001600182015481526020016002820154815260200160038201548152505090505f8483036131205785604001516fffffffffffffffffffffffffffffffff16613126565b81604001515b90505f5f83606001510361313a5742613140565b82606001515b90505f5f613175895f015167ffffffffffffffff1685856131619190614711565b61316b9190614f05565b86602001516134cb565b915091505f5f6131938c885f01518561318e9190614f73565b613519565b915091508380156131a15750815b6131ab578b6131ad565b805b9b50505050505050506001816131c3919061493a565b90506130ae565b50505050919050565b600a54811115613218576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161320f90614fed565b60405180910390fd5b80600a5f8282546132299190614711565b9250508190555061327d7f000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f3084847f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2612d79565b5050565b60605f5f8573ffffffffffffffffffffffffffffffffffffffff16856040516132aa919061503b565b5f60405180830381855af49150503d805f81146132e2576040519150601f19603f3d011682016040523d82523d5f602084013e6132e7565b606091505b50915091506132f886838387613545565b925050509392505050565b5f8373ffffffffffffffffffffffffffffffffffffffff168360405161332890615074565b5f6040518083038185875af1925050503d805f8114613362576040519150601f19603f3d011682016040523d82523d5f602084013e613367565b606091505b50509050806133f9578173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0846040518263ffffffff1660e01b81526004015f604051808303818588803b1580156133b6575f5ffd5b505af11580156133c8573d5f5f3e3d5ffd5b50505050506133f884848473ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b5b50505050565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603156134c5573073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16036134965761349182828673ffffffffffffffffffffffffffffffffffffffff166135b99092919063ffffffff16565b6134c4565b6134c38383838773ffffffffffffffffffffffffffffffffffffffff1661363f909392919063ffffffff16565b5b5b50505050565b5f5f5f84036134e05760015f91509150613512565b5f8385029050838582816134f7576134f6614f46565b5b0414613509575f5f9250925050613512565b60018192509250505b9250929050565b5f5f5f838501905084811015613535575f5f925092505061353e565b60018192509250505b9250929050565b606083156135a6575f83510361359e5761355e856136c8565b61359d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613594906150d2565b60405180910390fd5b5b8290506135b1565b6135b083836136ea565b5b949350505050565b61363a8363a9059cbb60e01b84846040516024016135d89291906150f0565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b505050565b6136c2846323b872dd60e01b85858560405160240161366093929190614771565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050613739565b50505050565b5f5f8273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b5f825111156136fc5781518083602001fd5b806040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137309190614267565b60405180910390fd5b5f61379a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166137fe9092919063ffffffff16565b90505f815111156137f957808060200190518101906137b99190615141565b6137f8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137ef906151dc565b60405180910390fd5b5b505050565b606061380c84845f85613815565b90509392505050565b60608247101561385a576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016138519061526a565b60405180910390fd5b5f5f8673ffffffffffffffffffffffffffffffffffffffff168587604051613882919061503b565b5f6040518083038185875af1925050503d805f81146138bc576040519150601f19603f3d011682016040523d82523d5f602084013e6138c1565b606091505b50915091506138d287838387613545565b92505050949350505050565b5f82825260208201905092915050565b7f63616c6c6572206e6f74206e617469766520746f6b656e20777261707065722e5f82015250565b5f6139226020836138de565b915061392d826138ee565b602082019050919050565b5f6020820190508181035f83015261394f81613916565b9050919050565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b61399b81613967565b81146139a5575f5ffd5b50565b5f813590506139b681613992565b92915050565b5f602082840312156139d1576139d061395f565b5b5f6139de848285016139a8565b91505092915050565b5f8115159050919050565b6139fb816139e7565b82525050565b5f602082019050613a145f8301846139f2565b92915050565b5f819050919050565b613a2c81613a1a565b82525050565b5f602082019050613a455f830184613a23565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f840112613a6c57613a6b613a4b565b5b8235905067ffffffffffffffff811115613a8957613a88613a4f565b5b602083019150836020820283011115613aa557613aa4613a53565b5b9250929050565b5f5f60208385031215613ac257613ac161395f565b5b5f83013567ffffffffffffffff811115613adf57613ade613963565b5b613aeb85828601613a57565b92509250509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613b2082613af7565b9050919050565b613b3081613b16565b8114613b3a575f5ffd5b50565b5f81359050613b4b81613b27565b92915050565b5f60208284031215613b6657613b6561395f565b5b5f613b7384828501613b3d565b91505092915050565b613b8581613a1a565b8114613b8f575f5ffd5b50565b5f81359050613ba081613b7c565b92915050565b5f5f83601f840112613bbb57613bba613a4b565b5b8235905067ffffffffffffffff811115613bd857613bd7613a4f565b5b602083019150836001820283011115613bf457613bf3613a53565b5b9250929050565b5f5f5f5f5f60808688031215613c1457613c1361395f565b5b5f613c2188828901613b3d565b9550506020613c3288828901613b3d565b9450506040613c4388828901613b92565b935050606086013567ffffffffffffffff811115613c6457613c63613963565b5b613c7088828901613ba6565b92509250509295509295909350565b613c8881613967565b82525050565b5f602082019050613ca15f830184613c7f565b92915050565b5f60208284031215613cbc57613cbb61395f565b5b5f613cc984828501613b92565b91505092915050565b613cdb81613b16565b82525050565b5f602082019050613cf45f830184613cd2565b92915050565b5f5f5f60408486031215613d1157613d1061395f565b5b5f84013567ffffffffffffffff811115613d2e57613d2d613963565b5b613d3a86828701613a57565b93509350506020613d4d86828701613b3d565b9150509250925092565b5f67ffffffffffffffff82169050919050565b613d7381613d57565b82525050565b5f6fffffffffffffffffffffffffffffffff82169050919050565b613d9d81613d79565b82525050565b5f608082019050613db65f830187613d6a565b613dc36020830186613d6a565b613dd06040830185613d94565b613ddd6060830184613a23565b95945050505050565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b613e3082613dea565b810181811067ffffffffffffffff82111715613e4f57613e4e613dfa565b5b80604052505050565b5f613e61613956565b9050613e6d8282613e27565b919050565b5f67ffffffffffffffff821115613e8c57613e8b613dfa565b5b613e9582613dea565b9050602081019050919050565b828183375f83830152505050565b5f613ec2613ebd84613e72565b613e58565b905082815260208101848484011115613ede57613edd613de6565b5b613ee9848285613ea2565b509392505050565b5f82601f830112613f0557613f04613a4b565b5b8135613f15848260208601613eb0565b91505092915050565b5f60208284031215613f3357613f3261395f565b5b5f82013567ffffffffffffffff811115613f5057613f4f613963565b5b613f5c84828501613ef1565b91505092915050565b5f5f83601f840112613f7a57613f79613a4b565b5b8235905067ffffffffffffffff811115613f9757613f96613a4f565b5b602083019150836020820283011115613fb357613fb2613a53565b5b9250929050565b5f5f60208385031215613fd057613fcf61395f565b5b5f83013567ffffffffffffffff811115613fed57613fec613963565b5b613ff985828601613f65565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f6140608261402e565b61406a8185614038565b935061407a818560208601614048565b61408381613dea565b840191505092915050565b5f6140998383614056565b905092915050565b5f602082019050919050565b5f6140b782614005565b6140c1818561400f565b9350836020820285016140d38561401f565b805f5b8581101561410e57848403895281516140ef858261408e565b94506140fa836140a1565b925060208a019950506001810190506140d6565b50829750879550505050505092915050565b5f6020820190508181035f83015261413881846140ad565b905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61417281613a1a565b82525050565b5f6141838383614169565b60208301905092915050565b5f602082019050919050565b5f6141a582614140565b6141af818561414a565b93506141ba8361415a565b805f5b838110156141ea5781516141d18882614178565b97506141dc8361418f565b9250506001810190506141bd565b5085935050505092915050565b5f6040820190508181035f83015261420f818561419b565b905061421e6020830184613a23565b9392505050565b5f81519050919050565b5f61423982614225565b61424381856138de565b9350614253818560208601614048565b61425c81613dea565b840191505092915050565b5f6020820190508181035f83015261427f818461422f565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6142be82613d57565b91506142c983613d57565b9250828203905067ffffffffffffffff8111156142e9576142e8614287565b5b92915050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c005f82015250565b5f614323601f836138de565b915061432e826142ef565b602082019050919050565b5f6020820190508181035f83015261435081614317565b9050919050565b7f446972656374207472616e7366657200000000000000000000000000000000005f82015250565b5f61438b600f836138de565b915061439682614357565b602082019050919050565b5f6020820190508181035f8301526143b88161437f565b9050919050565b7f4e6f7420617574686f72697a65640000000000000000000000000000000000005f82015250565b5f6143f3600e836138de565b91506143fe826143bf565b602082019050919050565b5f6020820190508181035f830152614420816143e7565b9050919050565b7f52657761726420756e6368616e6765642e0000000000000000000000000000005f82015250565b5f61445b6011836138de565b915061446682614427565b602082019050919050565b5f6020820190508181035f8301526144888161444f565b9050919050565b5f6040820190506144a25f830185613a23565b6144af6020830184613a23565b9392505050565b7f54696d652d756e697420756e6368616e6765642e0000000000000000000000005f82015250565b5f6144ea6014836138de565b91506144f5826144b6565b602082019050919050565b5f6020820190508181035f830152614517816144de565b9050919050565b7f4f6e6c79206f776e65722063616e20656d657267656e637920776974686472615f8201527f7700000000000000000000000000000000000000000000000000000000000000602082015250565b5f6145786021836138de565b91506145838261451e565b604082019050919050565b5f6020820190508181035f8301526145a58161456c565b9050919050565b7f43616e6e6f7420776974686472617720746f207a65726f2061646472657373005f82015250565b5f6145e0601f836138de565b91506145eb826145ac565b602082019050919050565b5f6020820190508181035f83015261460d816145d4565b9050919050565b7f426174636820746f6f206c6172676500000000000000000000000000000000005f82015250565b5f614648600f836138de565b915061465382614614565b602082019050919050565b5f6020820190508181035f8301526146758161463c565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f546f6b656e206e6f74207374616b6564000000000000000000000000000000005f82015250565b5f6146dd6010836138de565b91506146e8826146a9565b602082019050919050565b5f6020820190508181035f83015261470a816146d1565b9050919050565b5f61471b82613a1a565b915061472683613a1a565b925082820390508181111561473e5761473d614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f6060820190506147845f830186613cd2565b6147916020830185613cd2565b61479e6040830184613a23565b949350505050565b5f5ffd5b82818337505050565b5f6147be838561414a565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156147f1576147f06147a6565b5b6020830292506148028385846147aa565b82840190509392505050565b5f6020820190508181035f8301526148278184866147b3565b90509392505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f8335600160200384360303811261485857614857614830565b5b80840192508235915067ffffffffffffffff82111561487a57614879614834565b5b60208301925060018202360383131561489657614895614838565b5b509250929050565b5f81905092915050565b5f6148b3838561489e565b93506148c0838584613ea2565b82840190509392505050565b5f8160601b9050919050565b5f6148e2826148cc565b9050919050565b5f6148f3826148d8565b9050919050565b61490b61490682613b16565b6148e9565b82525050565b5f61491d8285876148a8565b915061492982846148fa565b601482019150819050949350505050565b5f61494482613a1a565b915061494f83613a1a565b925082820190508082111561496757614966614287565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806149b157607f821691505b6020821081036149c4576149c361496d565b5b50919050565b7f5374616b696e67203020746f6b656e73000000000000000000000000000000005f82015250565b5f6149fe6010836138de565b9150614a09826149ca565b602082019050919050565b5f6020820190508181035f830152614a2b816149f2565b9050919050565b5f614a3c82613d57565b9150614a4783613d57565b9250828201905067ffffffffffffffff811115614a6757614a66614287565b5b92915050565b5f81905092915050565b5f614a828385614a6d565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115614ab557614ab46147a6565b5b602083029250614ac68385846147aa565b82840190509392505050565b5f614ade828486614a77565b91508190509392505050565b5f81519050614af881613b7c565b92915050565b5f60208284031215614b1357614b1261395f565b5b5f614b2084828501614aea565b91505092915050565b7f74696d652d756e69742063616e277420626520300000000000000000000000005f82015250565b5f614b5d6014836138de565b9150614b6882614b29565b602082019050919050565b5f6020820190508181035f830152614b8a81614b51565b9050919050565b7f4e6f2072657761726473000000000000000000000000000000000000000000005f82015250565b5f614bc5600a836138de565b9150614bd082614b91565b602082019050919050565b5f6020820190508181035f830152614bf281614bb9565b9050919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302614c557fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82614c1a565b614c5f8683614c1a565b95508019841693508086168417925050509392505050565b5f819050919050565b5f614c9a614c95614c9084613a1a565b614c77565b613a1a565b9050919050565b5f819050919050565b614cb383614c80565b614cc7614cbf82614ca1565b848454614c26565b825550505050565b5f5f905090565b614cde614ccf565b614ce9818484614caa565b505050565b5b81811015614d0c57614d015f82614cd6565b600181019050614cef565b5050565b601f821115614d5157614d2281614bf9565b614d2b84614c0b565b81016020851015614d3a578190505b614d4e614d4685614c0b565b830182614cee565b50505b505050565b5f82821c905092915050565b5f614d715f1984600802614d56565b1980831691505092915050565b5f614d898383614d62565b9150826002028217905092915050565b614da282614225565b67ffffffffffffffff811115614dbb57614dba613dfa565b5b614dc5825461499a565b614dd0828285614d10565b5f60209050601f831160018114614e01575f8415614def578287015190505b614df98582614d7e565b865550614e60565b601f198416614e0f86614bf9565b5f5b82811015614e3657848901518255600182019150602085019450602081019050614e11565b86831015614e535784890151614e4f601f891682614d62565b8355505b6001600288020188555050505b505050505050565b5f6040820190508181035f830152614e80818561422f565b90508181036020830152614e94818461422f565b90509392505050565b7f4e46547320617265207065726d616e656e746c79207374616b656400000000005f82015250565b5f614ed1601b836138de565b9150614edc82614e9d565b602082019050919050565b5f6020820190508181035f830152614efe81614ec5565b9050919050565b5f614f0f82613a1a565b9150614f1a83613a1a565b9250828202614f2881613a1a565b91508282048414831517614f3f57614f3e614287565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f614f7d82613a1a565b9150614f8883613a1a565b925082614f9857614f97614f46565b5b828204905092915050565b7f4e6f7420656e6f7567682072657761726420746f6b656e7300000000000000005f82015250565b5f614fd76018836138de565b9150614fe282614fa3565b602082019050919050565b5f6020820190508181035f83015261500481614fcb565b9050919050565b5f6150158261402e565b61501f818561489e565b935061502f818560208601614048565b80840191505092915050565b5f615046828461500b565b915081905092915050565b50565b5f61505f5f8361489e565b915061506a82615051565b5f82019050919050565b5f61507e82615054565b9150819050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000005f82015250565b5f6150bc601d836138de565b91506150c782615088565b602082019050919050565b5f6020820190508181035f8301526150e9816150b0565b9050919050565b5f6040820190506151035f830185613cd2565b6151106020830184613a23565b9392505050565b615120816139e7565b811461512a575f5ffd5b50565b5f8151905061513b81615117565b92915050565b5f602082840312156151565761515561395f565b5b5f6151638482850161512d565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e5f8201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b5f6151c6602a836138de565b91506151d18261516c565b604082019050919050565b5f6020820190508181035f8301526151f3816151ba565b9050919050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f5f8201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b5f6152546026836138de565b915061525f826151fa565b604082019050919050565b5f6020820190508181035f83015261528181615248565b905091905056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212208d303b28d426b05eacbd0c12f762c5c0eb7ec880d79828074be3f892bfefaeb664736f6c634300081c0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000fac9746e0b49d2d3982b43e754f0fe64b9883d270000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000aa87bee5380000000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2

-----Decoded View---------------
Arg [0] : _defaultAdmin (address): 0xfAc9746E0b49d2D3982B43E754F0fE64b9883d27
Arg [1] : _timeUnit (uint256): 1
Arg [2] : _rewardsPerUnitTime (uint256): 3000000000000000
Arg [3] : _stakingToken (address): 0x3A40312A1C376aEcF855eF784371d1fb1AA2d25D
Arg [4] : _rewardToken (address): 0xa0C69824C820F36CA32666462405eA85F414409f
Arg [5] : _nativeTokenWrapper (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000fac9746e0b49d2d3982b43e754f0fe64b9883d27
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 000000000000000000000000000000000000000000000000000aa87bee538000
Arg [3] : 0000000000000000000000003a40312a1c376aecf855ef784371d1fb1aa2d25d
Arg [4] : 000000000000000000000000a0c69824c820f36ca32666462405ea85f414409f
Arg [5] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2


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

OVERVIEW

Locking NFTs to earn points on Cashmere campaigns.

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.