ETH Price: $1,950.80 (-0.62%)
 

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-03-01 1:56:5222 hrs ago1772330212IN
Cashmere: NFT Lock
0 ETH(Pending)(Pending)
Claim Rewards245661592026-03-02 0:23:2311 mins ago1772411003IN
Cashmere: NFT Lock
0 ETH0.000003430.04554717
Claim Rewards245660212026-03-01 23:55:3539 mins ago1772409335IN
Cashmere: NFT Lock
0 ETH0.000003280.04364052
Claim Rewards245654932026-03-01 22:09:592 hrs ago1772402999IN
Cashmere: NFT Lock
0 ETH0.00000720.09566662
Claim Rewards245654502026-03-01 22:01:232 hrs ago1772402483IN
Cashmere: NFT Lock
0 ETH0.000004080.05418561
Claim Rewards245654362026-03-01 21:58:352 hrs ago1772402315IN
Cashmere: NFT Lock
0 ETH0.000004770.06342772
Claim Rewards245653782026-03-01 21:46:592 hrs ago1772401619IN
Cashmere: NFT Lock
0 ETH0.000005960.07916559
Claim Rewards245652852026-03-01 21:28:233 hrs ago1772400503IN
Cashmere: NFT Lock
0 ETH0.000006110.08117495
Claim Rewards245651782026-03-01 21:06:593 hrs ago1772399219IN
Cashmere: NFT Lock
0 ETH0.000009760.1295454
Claim Rewards245651612026-03-01 21:03:353 hrs ago1772399015IN
Cashmere: NFT Lock
0 ETH0.000009590.12737054
Claim Rewards245651282026-03-01 20:56:593 hrs ago1772398619IN
Cashmere: NFT Lock
0 ETH0.000010360.13757218
Claim Rewards245651142026-03-01 20:54:113 hrs ago1772398451IN
Cashmere: NFT Lock
0 ETH0.000010620.14095738
Claim Rewards245648322026-03-01 19:57:354 hrs ago1772395055IN
Cashmere: NFT Lock
0 ETH0.000003910.0519955
Claim Rewards245648302026-03-01 19:57:114 hrs ago1772395031IN
Cashmere: NFT Lock
0 ETH0.000003910.05198718
Claim Rewards245647332026-03-01 19:37:474 hrs ago1772393867IN
Cashmere: NFT Lock
0 ETH0.000003630.04829162
Claim Rewards245646652026-03-01 19:24:115 hrs ago1772393051IN
Cashmere: NFT Lock
0 ETH0.000003090.04105095
Claim Rewards245646622026-03-01 19:23:355 hrs ago1772393015IN
Cashmere: NFT Lock
0 ETH0.000003530.04688166
Claim Rewards245646612026-03-01 19:23:235 hrs ago1772393003IN
Cashmere: NFT Lock
0 ETH0.000003580.04751552
Claim Rewards245644542026-03-01 18:41:595 hrs ago1772390519IN
Cashmere: NFT Lock
0 ETH0.00000430.05707319
Claim Rewards245644352026-03-01 18:38:115 hrs ago1772390291IN
Cashmere: NFT Lock
0 ETH0.000079491.05484593
Claim Rewards245643802026-03-01 18:27:116 hrs ago1772389631IN
Cashmere: NFT Lock
0 ETH0.00000650.08632627
Claim Rewards245643272026-03-01 18:16:356 hrs ago1772388995IN
Cashmere: NFT Lock
0 ETH0.000006930.09203784
Claim Rewards245643182026-03-01 18:14:476 hrs ago1772388887IN
Cashmere: NFT Lock
0 ETH0.000007930.10535091
Claim Rewards245643132026-03-01 18:13:476 hrs ago1772388827IN
Cashmere: NFT Lock
0 ETH0.000007880.10460311
Claim Rewards245642992026-03-01 18:10:596 hrs ago1772388659IN
Cashmere: NFT Lock
0 ETH0.000008890.11800129
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
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.