ETH Price: $2,551.89 (-1.89%)

Contract

0x2e1A4cfEF2B02055AA3E36b5208dfe7C31F3FfAF
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Unstake Nft148296442022-05-23 12:43:10884 days ago1653309790IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0017638720.94668515
Unstake Nft143935362022-03-15 21:14:12953 days ago1647378852IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0027807434.60011119
Stake Nft141579082022-02-07 8:33:57989 days ago1644222837IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0142339485.22808105
Unstake Nft138334162021-12-19 4:31:411040 days ago1639888301IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0043505454.13286175
Unstake Nft138334112021-12-19 4:30:301040 days ago1639888230IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0041077848.78135516
Unstake Nft138334072021-12-19 4:28:451040 days ago1639888125IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0041241547.8290583
Unstake Nft138334052021-12-19 4:27:311040 days ago1639888051IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0034380138.93299561
Unstake Nft138333982021-12-19 4:26:041040 days ago1639887964IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0038560943.54610553
Unstake Nft138333942021-12-19 4:25:021040 days ago1639887902IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0038101738.81909554
Unstake Nft138333882021-12-19 4:24:151040 days ago1639887855IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0044585745.31160934
Unstake Nft138333842021-12-19 4:23:361040 days ago1639887816IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0046908846.48078851
Unstake Nft138333792021-12-19 4:21:451040 days ago1639887705IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0050629348.94375883
Unstake Nft138333762021-12-19 4:21:361040 days ago1639887696IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0047047144.39792219
Unstake Nft138333732021-12-19 4:19:331040 days ago1639887573IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0049396844.59524444
Unstake Nft138333672021-12-19 4:18:011040 days ago1639887481IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0048750543.03167469
Unstake Nft138333612021-12-19 4:16:411040 days ago1639887401IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0046984440.56920806
Unstake Nft138333522021-12-19 4:14:391040 days ago1639887279IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0050320344.3210112
Unstake Nft138333472021-12-19 4:13:381040 days ago1639887218IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0051506244.37934826
Unstake Nft138333372021-12-19 4:11:291040 days ago1639887089IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.004667939.36436544
Unstake Nft138333312021-12-19 4:10:531040 days ago1639887053IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0064138252.96083097
Unstake Nft138333272021-12-19 4:08:461040 days ago1639886926IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0049293839.87270967
Unstake Nft138333212021-12-19 4:08:051040 days ago1639886885IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.005637644.68936776
Unstake Nft138333082021-12-19 4:04:501040 days ago1639886690IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.0054315542.21178827
Unstake Nft138333032021-12-19 4:03:471040 days ago1639886627IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.004018450
Unstake Nft138332882021-12-19 3:59:221040 days ago1639886362IN
0x2e1A4cfE...C31F3FfAF
0 ETH0.003754842.63917346
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LpNftStakingFarm

Compiler Version
v0.8.3+commit.8d00100c

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : LpNftStakingFarm.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.3;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "./ERC20Interface.sol";
import "./IUniswapV2Pair.sol";
import "./Calculator.sol";
import "./erc1155/ERC1155TokenReceiver.sol";

/**
 * lp nft staking farm
 */
contract LpNftStakingFarm is
    Context,
    Ownable,
    ReentrancyGuard,
    Pausable,
    ERC1155TokenReceiver
{
    using Address for address;
    using SafeMath for uint256;
    using Calculator for uint256;

    /**
     * Emitted when a user store farming rewards(ERC20 token).
     * @param sender User address.
     * @param amount Current store amount.
     * @param timestamp The time when store farming rewards.
     */
    event ContractFunded(
        address indexed sender,
        uint256 amount,
        uint256 timestamp
    );

    /**
     * Emitted when a user stakes tokens(ERC20 token).
     * @param sender User address.
     * @param balance Current user balance.
     * @param timestamp The time when stake tokens.
     */
    event Staked(address indexed sender, uint256 balance, uint256 timestamp);

    /**
     * Emitted when a user unstakes erc20 tokens.
     * @param sender User address.
     * @param apy The apy of user.
     * @param balance The balance of user.
     * @param umiInterest The amount of interest(umi token).
     * @param timePassed TimePassed seconds.
     * @param timestamp The time when unstake tokens.
     */
    event Unstaked(
        address indexed sender,
        uint256 apy,
        uint256 balance,
        uint256 umiInterest,
        uint256 timePassed,
        uint256 timestamp
    );

    /**
     * Emitted when a new BASE_APY value is set.
     * @param value A new APY value.
     * @param sender The owner address at the moment of BASE_APY changing.
     */
    event BaseApySet(uint256 value, address sender);

    /**
     * Emitted when a new nft apy value is set.
     * @param nftAddress The address of nft contract.
     * @param nftId The nft id.
     * @param value A new APY value.
     * @param sender The owner address at the moment of apy changing.
     */
    event NftApySet(address indexed nftAddress, uint256 nftId, uint256 value, address sender);

    /**
     * Emitted when a user stakes nft token.
     * @param sender User address.
     * @param nftAddress The address of nft contract.
     * @param nftId The nft id.
     * @param amount The amount of nft id.
     * @param timestamp The time when stake nft.
     */
    event NftStaked(
        address indexed sender,
        address indexed nftAddress,
        uint256 nftId,
        uint256 amount,
        uint256 timestamp
    );

    /**
     * Emitted when a user batch stakes nft token.
     * @param sender User address.
     * @param nftAddress The address of nft contract.
     * @param nftIds The nft id.
     * @param amounts The amount of nft id.
     * @param timestamp The time when batch stake nft.
     */
    event NftsBatchStaked(
        address indexed sender,
        address indexed nftAddress,
        uint256[] nftIds,
        uint256[] amounts,
        uint256 timestamp
    );

    /**
     * Emitted when a user unstake nft token.
     * @param sender User address.
     * @param nftAddress The address of nft contract.
     * @param nftId The nft id.
     * @param amount The amount of nft id.
     * @param timestamp The time when unstake nft.
     */
    event NftUnstaked(
        address indexed sender,
        address indexed nftAddress,
        uint256 nftId,
        uint256 amount,
        uint256 timestamp
    );

    /**
     * Emitted when a user batch unstake nft token.
     * @param sender User address.
     * @param nftAddress The address of nft contract.
     * @param nftIds The nft id array.
     * @param amounts The amount array of nft id.
     * @param timestamp The time when batch unstake nft.
     */
    event NftsBatchUnstaked(
        address indexed sender,
        address indexed nftAddress,
        uint256[] nftIds,
        uint256[] amounts,
        uint256 timestamp
    );

    /**
     * @dev Emitted when a user withdraw interest only.
     * @param sender User address.
     * @param principal The principal of user.
     * @param interest The amount of interest.
     * @param claimTimestamp claim timestamp.
     */
    event Claimed(
        address indexed sender,
        uint256 principal,
        uint256 interest,
        uint256 claimTimestamp
    );

    // lp token
    IUniswapV2Pair public lpToken;
    // rewards token(umi token now)
    ERC20Interface public umiToken;

    // lp token about
    // The stake balances of users, it will contains interest(user address->amount), input token is umi
    mapping(address => uint256) public balances;
    // The dates of users' stakes(user address->timestamp)
    mapping(address => uint256) public stakeDates;
    // The total staked amount
    uint256 public totalStaked;

    // umi token about
    // The farming rewards of users(address => total amount)
    mapping(address => uint256) public funding;
    // The total farming rewards for users
    uint256 public totalFunding;

    // ERC1155 about
    // Store each nft apy(nft address->(ntfId->apy))
    mapping(address => mapping(uint256 => uint8)) public nftApys;
    // Nft balance of users(user address->(nft contract address -> (nftId->amount)))
    mapping(address => mapping(address => mapping(uint256 => uint256))) public nftBalances;
    // Store user's nft ids(user address -> (nft contract address -> NftSet))
    mapping(address => mapping(address => NftSet)) userNftIds;
    // The total nft staked amount
    uint256 public totalNftStaked;
    // To store user's nft ids, it is more convenient to know if nft id of user exists
    struct NftSet {
        // user's nft id array
        uint256[] ids;
        // nft id -> bool, if nft id exist
        mapping(uint256 => bool) isIn;
    }
    // the nft contracts address which supported
    address[] public nftAddresses;
    // if nft address supported
    mapping(address => bool) public isNftSupported;
    address private firstNft = 0xd194f079Cc291Fe9DB7Dad95444eEc1246413636;
    address private secondNft = 0x90ad78735BC59a5dCb6a038728684c484CD5860D;

    // other constants
    // base APY when staking just lp token is 33%, only contract owner can modify it
    uint256 public BASE_APY = 33; // stand for 33%

    constructor(address _umiAddress, address _lpAddress) {
        require(
            _umiAddress.isContract() && _lpAddress.isContract(),
            "must use contract address"
        );
        umiToken = ERC20Interface(_umiAddress);
        lpToken = IUniswapV2Pair(_lpAddress);
        
        nftAddresses.push(firstNft);
        nftAddresses.push(secondNft);
        isNftSupported[firstNft] = true;
        isNftSupported[secondNft] = true;
        
        // initialize apys
        initApys();
    }

    /**
     * Store farming rewards to UmiStakingFarm contract, in order to pay the user interest later.
     *
     * Note: _amount should be more than 0
     * @param _amount The amount to funding contract.
     */
    function fundingContract(uint256 _amount) external nonReentrant {
        require(_amount > 0, "_amount should be more than 0");
        funding[msg.sender] += _amount;
        // increase total funding
        totalFunding += _amount;
        require(
            umiToken.transferFrom(msg.sender, address(this), _amount),
            "transferFrom failed"
        );
        // send event
        emit ContractFunded(msg.sender, _amount, _now());
    }

    /**
     * Only owner can set base apy.
     *
     * Note: If you want to set apy 12%, just pass 12
     *
     * @param _APY annual percentage yield
     */
    function setBaseApy(uint256 _APY) public onlyOwner {
        BASE_APY = _APY;
        emit BaseApySet(BASE_APY, msg.sender);
    }

    /**
     * This method is used to stake tokens(input token is LpToken).
     * Note: It calls another internal "_stake" method. See its description.
     * @param _amount The amount to stake.
     */
    function stake(uint256 _amount) public whenNotPaused nonReentrant {
        _stake(msg.sender, _amount);
    }

    /**
     * Increases the user's balance, totalStaked and updates the stake date.
     * @param _sender The address of the sender.
     * @param _amount The amount to stake.
     */
    function _stake(address _sender, uint256 _amount) internal {
        require(_amount > 0, "stake amount should be more than 0");
        // calculate rewards of umi token
        uint256 umiInterest = calculateUmiTokenRewards(_sender);

        // increase balances
        balances[_sender] = balances[_sender].add(_amount);
        // increase totalStaked
        totalStaked = totalStaked.add(_amount);
        uint256 stakeTimestamp = _now();
        stakeDates[_sender] = stakeTimestamp;
        // send staked event
        emit Staked(_sender, _amount, stakeTimestamp);
        // transfer lp token to contract
        require(
            lpToken.transferFrom(_sender, address(this), _amount),
            "transfer failed"
        );
        // Transfer umiToken interest to user
        transferUmiInterest(_sender, umiInterest);
    }
    
    /**
     * Transfer umiToken interest to user.
     */ 
    function transferUmiInterest(address recipient, uint256 amount) internal {
        if (amount <= 0) {
            return;
        }
        // reduce total funding
        totalFunding = totalFunding.sub(amount);
        require(
                umiToken.transfer(recipient, amount),
                "transfer umi interest failed"
            );
    }

    /**
     * This method is used to unstake all the amount of lp token.
     * Note: It calls another internal "_unstake" method. See its description.
     * Note: unstake lp token.
     */
    function unstake() external whenNotPaused nonReentrant {
        _unstake(msg.sender);
    }

    /**
     * Call internal "calculateRewardsAndTimePassed" method to calculate user's latest balance,
     * and then transfer tokens to the sender.
     *
     * @param _sender The address of the sender.
     */
    function _unstake(address _sender) internal {
        // get lp token balance of current user
        uint256 balance = balances[msg.sender];
        require(balance > 0, "insufficient funds");
        // calculate total balance with interest(the interest is umi token)
        (uint256 totalWithInterest, uint256 principalOfRepresentUmi, uint256 timePassed) =
            calculateRewardsAndTimePassed(_sender, 0);
        require(
            totalWithInterest > 0 && timePassed > 0,
            "totalWithInterest<=0 or timePassed<=0"
        );
        // update balance of user to 0
        balances[_sender] = 0;
        // update date of stake
        stakeDates[_sender] = 0;
        // update totalStaked of lpToken
        totalStaked = totalStaked.sub(balance);

        // interest to be paid, rewards is umi token
        uint256 interest = totalWithInterest.sub(principalOfRepresentUmi);
        uint256 umiInterestAmount = 0;
        if (interest > 0 && totalFunding >= interest) {
            // interest > 0 and total funding is enough to pay interest
            umiInterestAmount = interest;
            // reduce total funding
            totalFunding = totalFunding.sub(interest);
        }
        // total funding is not enough to pay interest, the contract's UMI has been completely drained. make sure users can unstake their lp tokens.
        // 1. rewards are paid in more umi
        if (umiInterestAmount > 0) {
            require(
                umiToken.transfer(_sender, umiInterestAmount),
                "_unstake umi transfer failed"
            );
        }
        // 2. unstake lp token of user
        require(
            lpToken.transfer(_sender, balance),
            "_unstake: lp transfer failed"
        );
        // send event
        emit Unstaked(
            _sender,
            getTotalApyOfUser(_sender),
            balance,
            umiInterestAmount,
            timePassed,
            _now()
        );
    }

    /**
     * stake nft token to this contract.
     * Note: It calls another internal "_stakeNft" method. See its description.
     * 
     * @param nftAddress The address of nft contract.
     */
    function stakeNft(
        address nftAddress,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external whenNotPaused nonReentrant {
        require(isInWhitelist(nftAddress, id), "stakeNft: nft id not in whitelist");
        _stakeNft(msg.sender, address(this), nftAddress, id, value, data);
    }

    /**
     * Transfers `_value` tokens of token type `_id` from `_from` to `_to`.
     *
     * Note: when nft staked, apy will changed, should recalculate balance.
     * update nft balance, nft id, totalNftStaked.
     *
     * @param _from The address of the sender.
     * @param _to The address of the receiver.
     * @param _nftAddress The address of nft contract.
     * @param _id The nft id.
     * @param _value The amount of nft token.
     */
    function _stakeNft(
        address _from,
        address _to,
        address _nftAddress,
        uint256 _id,
        uint256 _value,
        bytes calldata _data
    ) internal {
        // calculate rewards of umi token
        uint256 umiInterest = calculateUmiTokenRewards(_from);
        // update stakeDate of user
        stakeDates[_from] = balances[_from] > 0 ?  _now() : 0;

        // modify nftBalances of user
        nftBalances[_from][_nftAddress][_id] = nftBalances[_from][_nftAddress][_id].add(_value);
        // modify user's nft id array
        setUserNftIds(_from, _nftAddress, _id);
        totalNftStaked = totalNftStaked.add(_value);

        // transfer nft token to this contract
        getERC1155(_nftAddress).safeTransferFrom(_from, _to, _id, _value, _data);
        // Transfer umiToken interest to user
        transferUmiInterest(_from, umiInterest);
        // send event
        emit NftStaked(_from, _nftAddress, _id, _value, _now());
    }

    /**
     * Batch stake nft token to this contract.
     *
     * Note: It calls another internal "_batchStakeNfts" method. See its description.
     *       Reverts if ids and values length mismatch.
     * 
     * @param nftAddress The address of nft contract.
     * @param ids The nft id array to be staked.
     * @param values The nft amount array.
     */
    function batchStakeNfts(
        address nftAddress,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external whenNotPaused nonReentrant {
        require(
            ids.length == values.length,
            "ids and values length mismatch"
        );
        _batchStakeNfts(msg.sender, address(this), nftAddress, ids, values, data);
    }

    /**
     * Batch transfers `_values` tokens of token type `_ids` from `_from` to `_to`.
     *
     * Note: when nft staked, apy will changed, should recalculate balance.
     * update nft balance, nft id and totalNftStaked.
     *
     * @param _from The address of sender.
     * @param _to The address of receiver.
     * @param _nftAddress The address of nft contract.
     * @param _ids The nft id array to be staked.
     * @param _values The nft amount array.
     */
    function _batchStakeNfts(
        address _from,
        address _to,
        address _nftAddress,
        uint256[] memory _ids,
        uint256[] memory _values,
        bytes calldata _data
    ) internal {
        // calculate rewards of umi token
        uint256 umiInterest = calculateUmiTokenRewards(_from);
        // update stakeDate of user
        stakeDates[_from] = balances[_from] > 0 ?  _now() : 0;

        // update data
        for (uint256 i = 0; i < _ids.length; i++) {
            // get nft id from id array
            uint256 id = _ids[i];
            // get amount
            uint256 value = _values[i];

            require(isInWhitelist(_nftAddress, id), "nft id not in whitelist");

            // increase nft balance of user
            nftBalances[_from][_nftAddress][id] = nftBalances[_from][_nftAddress][id].add(value);
            // update user's nft id array
            setUserNftIds(_from, _nftAddress, id);
            // increase total nft amount
            totalNftStaked = totalNftStaked.add(value);
        }

        // batch transfer nft tokens
        getERC1155(_nftAddress).safeBatchTransferFrom(_from, _to, _ids, _values, _data);
        // Transfer umiToken interest to user
        transferUmiInterest(msg.sender, umiInterest);
        // send event
        emit NftsBatchStaked(_from, _nftAddress, _ids, _values, _now());
    }

    /**
     * Unstake nft token from this contract.
     *
     * Note: It calls another internal "_unstakeNft" method. See its description.
     *
     * @param nftAddress The address of nft contract.
     * @param id The nft id.
     * @param value The amount of nft id.
     */
    function unstakeNft(
        address nftAddress,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external whenNotPaused nonReentrant {
        _unstakeNft(nftAddress, id, value, data);
    }

    /**
     * Unstake nft token with sufficient balance.
     *
     * Note: when nft unstaked, apy will changed, should recalculate balance.
     * update nft balance, nft id and totalNftStaked.
     *
     * @param _nftAddress The address of nft contract.
     * @param _id The nft id.
     * @param _value The amount of nft id.
     */
    function _unstakeNft(
        address _nftAddress,
        uint256 _id,
        uint256 _value,
        bytes calldata _data
    ) internal {
        // calculate rewards of umi token
        uint256 umiInterest = calculateUmiTokenRewards(msg.sender);
        // update stakeDate of user
        stakeDates[msg.sender] = balances[msg.sender] > 0 ?  _now() : 0;

        uint256 nftBalance = nftBalances[msg.sender][_nftAddress][_id];
        require(
            nftBalance >= _value,
            "insufficient balance for unstake"
        );

        // reduce nft balance
        nftBalances[msg.sender][_nftAddress][_id] = nftBalance.sub(_value);
        // reduce total nft amount
        totalNftStaked = totalNftStaked.sub(_value);
        if (nftBalances[msg.sender][_nftAddress][_id] == 0) {
            // if balance of the nft id is 0, remove nft id and set flag=false
            removeUserNftId(_nftAddress, _id);
        }

        // transfer nft token from this contract
        getERC1155(_nftAddress).safeTransferFrom(
            address(this),
            msg.sender,
            _id,
            _value,
            _data
        );
        // Transfer umiToken interest to user
        transferUmiInterest(msg.sender, umiInterest);
        // send event
        emit NftUnstaked(msg.sender, _nftAddress, _id, _value, _now());
    }

    /**
     * Batch unstake nft token from this contract.
     *
     * Note: It calls another internal "_batchUnstakeNfts" method. See its description.
     *       Reverts if ids and values length mismatch.
     *
     * @param nftAddress The address of nft contract.
     * @param ids The nft id array to be staked.
     * @param values The nft amount array.
     */
    function batchUnstakeNfts(
        address nftAddress,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external whenNotPaused nonReentrant {
        require(
            ids.length == values.length,
            "ids and values length mismatch"
        );
        _batchUnstakeNfts(address(this), msg.sender, nftAddress, ids, values, data);
    }

    /**
     * Batch unstake nft token from this contract.
     *
     * Note: when nft unstaked, apy will changed, should recalculate balance.
     * update nft balance, nft id and totalNftStaked.
     *
     * @param _from The address of sender.
     * @param _to The address of receiver.
     * @param _nftAddress The address of nft contract.
     * @param _ids The nft id array to be unstaked.
     * @param _values The nft amount array.
     */
    function _batchUnstakeNfts(
        address _from,
        address _to,
        address _nftAddress,
        uint256[] calldata _ids,
        uint256[] calldata _values,
        bytes calldata _data
    ) internal {
        // calculate rewards of umi token
        uint256 umiInterest = calculateUmiTokenRewards(_from);
        // update stakeDate of user
        stakeDates[_from] = balances[_from] > 0 ?  _now() : 0;

        // update data
        for (uint256 i = 0; i < _ids.length; i++) {
            // get nft id
            uint256 id = _ids[i];
            // get amount of nft id
            uint256 value = _values[i];

            uint256 nftBalance = nftBalances[msg.sender][_nftAddress][id];
            require(
                nftBalance >= value,
                "insufficient nft balance for unstake"
            );
            nftBalances[msg.sender][_nftAddress][id] = nftBalance.sub(value);
            totalNftStaked = totalNftStaked.sub(value);
            if (nftBalances[msg.sender][_nftAddress][id] == 0) {
                // if balance of the nft id is 0, remove nft id and set flag=false
                removeUserNftId(_nftAddress, id);
            }
        }

        // transfer nft token from this contract
        getERC1155(_nftAddress).safeBatchTransferFrom(_from, _to, _ids, _values, _data);
        // Transfer umiToken interest to user
        transferUmiInterest(msg.sender, umiInterest);
        // send event
        emit NftsBatchUnstaked(msg.sender, _nftAddress, _ids, _values, _now());
    }

    /**
    * Withdraws the interest only of user, and updates the stake date, balance and etc..
    */
    function claim() external whenNotPaused nonReentrant {
        uint256 balance = balances[msg.sender];
        require(balance > 0, "balance should more than 0");
        // calculate total balance with interest
        (uint256 totalWithInterest, uint256 principalOfRepresentUmi, uint256 timePassed) = calculateRewardsAndTimePassed(msg.sender, 0);
        require(
            totalWithInterest > 0 && timePassed >= 0,
            "calculate rewards and TimePassed error"
        );
        // interest to be paid
        uint256 interest = totalWithInterest.sub(principalOfRepresentUmi);
        require(interest > 0, "claim interest must more than 0");
        require(totalFunding >= interest, "total funding not enough to pay interest");
        // enough to pay interest
        // reduce total funding
        totalFunding = totalFunding.sub(interest);
        uint256 claimTimestamp = _now();
        // update stake date
        stakeDates[msg.sender] = claimTimestamp;
        // transfer interest to user
        require(
            umiToken.transfer(msg.sender, interest),
            "claim: transfer failed"
        );
        // send claim event
        emit Claimed(msg.sender, balance, interest, claimTimestamp);
    }

    /**
     * Calculate user's umiToken rewards.
     *
     * @param _from User address.
     */
    function calculateUmiTokenRewards(address _from) public view returns(uint256) {
        // if lpToken balance>0, pass time > 1 seconds, should calculate rewards of umiToken.
        // get current lp token balance
        uint256 balance = balances[_from];
        if (balance <= 0) {
            // stake first time, balance is 0, donot need to calculate rewards.
            return 0;
        }
        // calculate total balance with interest
        (uint256 totalWithInterest, uint principalOfRepresentUmi, uint256 timePassed) =
            calculateRewardsAndTimePassed(_from, 0);
        require(
            totalWithInterest > 0 && timePassed >= 0,
            "calculate rewards and TimePassed error"
        );
        // return rewards amount
        return totalWithInterest.sub(principalOfRepresentUmi);
    }

    /**
     * Calculate interest and time passed.
     *
     * @param _user User's address.
     * @param _amount Amount based on which interest is calculated. When 0, current stake balance is used.
     * @return Return total with interest and time passed.
     */
    function calculateRewardsAndTimePassed(address _user, uint256 _amount)
        internal
        view
        returns (uint256, uint256, uint256)
    {
        // current amount of lp token staked in contract
        uint256 currentBalance = balances[_user];
        uint256 amount = _amount == 0 ? currentBalance : _amount;
        uint256 stakeDate = stakeDates[_user];
        // seconds
        uint256 timePassed = _now().sub(stakeDate);
        if (timePassed < 1 seconds) {
            // if timePassed less than one second, rewards will be 0
            return (0, 0, timePassed);
        }
        // get total apy of user
        uint256 totalApy = getTotalApyOfUser(_user);
        // get lp token total supply
        uint256 lpTokenTotalSupply = lpToken.totalSupply();
        (uint112 umiReserve,,) = lpToken.getReserves();
        uint256 principalOfRepresentUmi = Calculator.getValueOfRepresentUmi(amount, lpTokenTotalSupply, umiReserve);
        uint256 totalWithInterest =
            Calculator.calculator(principalOfRepresentUmi, timePassed, totalApy);
        return (totalWithInterest, principalOfRepresentUmi, timePassed);
    }

    /**
     * Get umi token balance by address.
     * @param addr The address of the account that needs to check the balance.
     * @return Return balance of umi token.
     */
    function getUmiBalance(address addr) public view returns (uint256) {
        return umiToken.balanceOf(addr);
    }
    
    /**
     * Get erc1155 token instance by address.
     */
    function getERC1155(address _nftAddress) internal pure returns(IERC1155) {
       IERC1155 nftContract = IERC1155(_nftAddress);
       return nftContract;
    }

    /**
     * Get lp token balance by address.
     * @param addr The address of the account that needs to check the balance
     * @return Return balance of lp token.
     */
    function getLpBalance(address addr) public view returns (uint256) {
        return lpToken.balanceOf(addr);
    }

    /**
     * Get nft balance by user address and nft id.
     *
     * @param user The address of user.
     * @param nftAddress The address of nft contract.
     * @param id The nft id.
     */
    function getNftBalance(address user, address nftAddress, uint256 id)
        public
        view
        returns (uint256)
    {
        return getERC1155(nftAddress).balanceOf(user, id);
    }

    /**
     * Get user's nft ids array.
     * @param user The address of user.
     * @param nftAddress The address of nft contract.
     */
    function getUserNftIds(address user, address nftAddress)
        public
        view
        returns (uint256[] memory)
    {
        return userNftIds[user][nftAddress].ids;
    }

    /**
     * Get length of user's nft id array.
     * @param user The address of user.
     * @param nftAddress The address of nft contract.
     */
    function getUserNftIdsLength(address user, address nftAddress) public view returns (uint256) {
        return userNftIds[user][nftAddress].ids.length;
    }

    /**
     * Check whether user have certain nft or not.
     * @param user The address of user.
     * @param nftAddress The address of nft contract.
     * @param nftId The nft id of user.
     */
    function isNftIdExist(address user, address nftAddress, uint256 nftId)
        public
        view
        returns (bool)
    {
        NftSet storage nftSet = userNftIds[user][nftAddress];
        mapping(uint256 => bool) storage isIn = nftSet.isIn;
        return isIn[nftId];
    }

    /**
     * Set user's nft id.
     *
     * Note: when nft id donot exist, the nft id will be added to ids array, and the idIn flag will be setted true;
     * otherwise do nothing.
     *
     * @param user The address of user.
     * @param nftAddress The address of nft contract.
     * @param nftId The nft id of user.
     */
    function setUserNftIds(address user, address nftAddress, uint256 nftId) internal {
        NftSet storage nftSet = userNftIds[user][nftAddress];
        uint256[] storage ids = nftSet.ids;
        mapping(uint256 => bool) storage isIn = nftSet.isIn;
        if (!isIn[nftId]) {
            ids.push(nftId);
            isIn[nftId] = true;
        }
    }

    /**
     * Remove nft id of user.
     *
     * Note: when user's nft id amount=0, remove it from nft ids array, and set flag=false
     * 
     * @param nftAddress The address of nft contract.
     * @param nftId The nft id of user.
     */
    function removeUserNftId(address nftAddress, uint256 nftId) internal {
        NftSet storage nftSet = userNftIds[msg.sender][nftAddress];
        uint256[] storage ids = nftSet.ids;
        mapping(uint256 => bool) storage isIn = nftSet.isIn;
        require(ids.length > 0, "remove user nft ids, ids length must > 0");

        // find nftId index
        for (uint256 i = 0; i < ids.length; i++) {
            if (ids[i] == nftId) {
                ids[i] = ids[ids.length - 1];
                isIn[nftId] = false;
                ids.pop();
            }
        }
    }

    /**
     * Set apy of nft.
     *
     * Note: apy will be an integer value, 40 stands for 40%
     */
    function setApyByTokenId(address nftAddress, uint256 id, uint8 apy) public onlyOwner {
        require(nftAddress != address(0), "nft address incorrect");
        require(id > 0 && apy > 0, "nft and apy must > 0");
        if (!isNftSupported[nftAddress]) {
           // if nft address never been added
           nftAddresses.push(nftAddress);
           isNftSupported[nftAddress] = true;
        }
        nftApys[nftAddress][id] = apy;
        emit NftApySet(nftAddress, id, apy, msg.sender);
    }

    /**
     * Check if nft id is in whitelist.
     * @param id The nft id.
     */
    function isInWhitelist(address nftAddress, uint256 id) public view returns(bool) {
        return nftApys[nftAddress][id] > 0;
    }

    /**
     * Get user's total apy.
     *
     * Note: when umi token staked, base apy will be 12%; otherwise total apy will be 0.
     *
     * @param user The address of user.
     */
    function getTotalApyOfUser(address user) public view returns (uint256) {
        uint256 balanceOfUmi = balances[user];
        // if umi balance=0, the apy will be 0
        if (balanceOfUmi <= 0) {
            return 0;
        }
        // totalApy
        uint256 totalApy = BASE_APY;
        
        for (uint256 i = 0; i< nftAddresses.length; i++) {
            uint256[] memory nftIds = getUserNftIds(user, nftAddresses[i]);
            if (nftIds.length <= 0) {
                continue;
            }
            // iter nftIds and calculate total apy
            for (uint256 j = 0; j < nftIds.length; j++) {
                uint256 nftId = nftIds[j];
                // get user balance of nft
                uint256 balance = nftBalances[user][nftAddresses[i]][nftId];
                // get apy of certain nft id
                uint256 apy = nftApys[nftAddresses[i]][nftId];
                totalApy = totalApy.add(balance.mul(apy));
            }
        }
        
        return totalApy;
    }

    /**
     * @return Returns current timestamp.
     */
    function _now() internal view returns (uint256) {
        // Note that the timestamp can have a 900-second error:
        // https://github.com/ethereum/wiki/blob/c02254611f218f43cbb07517ca8e5d00fd6d6d75/Block-Protocol-2.0.md
        return block.timestamp; // solium-disable-line security/no-block-members
    }

    /**
     * Pauses all token stake, unstake.
     *
     * See {Pausable-_pause}.
     *
     * Requirements: the caller must be the owner.
     */
    function pause() public onlyOwner {
        _pause();
    }

    /**
     * Unpauses all token stake, unstake.
     *
     * See {Pausable-_unpause}.
     *
     * Requirements: the caller must be the owner.
     */
    function unpause() public onlyOwner {
        _unpause();
    }

    /**
     * Init apys when deploy contract.
     */
    function initApys() internal onlyOwner {
        // first nft contract
        // category 1(total 1)
        nftApys[firstNft][59] = 1;
        // category 2(total 3)
        nftApys[firstNft][18] = 2;
        nftApys[firstNft][19] = 2;
        nftApys[firstNft][20] = 2;
        // category 3(total 27)
        nftApys[firstNft][1] = 10;
        nftApys[firstNft][2] = 10;
        nftApys[firstNft][4] = 10;
        nftApys[firstNft][5] = 10;
        nftApys[firstNft][6] = 10;
        nftApys[firstNft][7] = 10;
        nftApys[firstNft][8] = 10;
        nftApys[firstNft][9] = 10;
        nftApys[firstNft][12] = 10;
        nftApys[firstNft][13] = 10;
        nftApys[firstNft][14] = 10;
        nftApys[firstNft][15] = 10;
        nftApys[firstNft][16] = 10;
        nftApys[firstNft][22] = 10;
        nftApys[firstNft][23] = 10;
        nftApys[firstNft][24] = 10;
        nftApys[firstNft][26] = 10;
        nftApys[firstNft][27] = 10;
        nftApys[firstNft][28] = 10;
        nftApys[firstNft][29] = 10;
        nftApys[firstNft][30] = 10;
        nftApys[firstNft][31] = 10;
        nftApys[firstNft][32] = 10;
        nftApys[firstNft][33] = 10;
        nftApys[firstNft][35] = 10;
        nftApys[firstNft][36] = 10;
        nftApys[firstNft][37] = 10;
        // category 4(total 4)
        nftApys[firstNft][3] = 20;
        nftApys[firstNft][11] = 20;
        nftApys[firstNft][25] = 20;
        nftApys[firstNft][34] = 20;
        // category 5(total 1)
        nftApys[firstNft][17] = 30;
        // category 6(total 7)
        nftApys[firstNft][38] = 40;
        nftApys[firstNft][39] = 40;
        nftApys[firstNft][40] = 40;
        nftApys[firstNft][41] = 40;
        nftApys[firstNft][42] = 40;
        nftApys[firstNft][43] = 40;
        nftApys[firstNft][44] = 40;

        nftApys[firstNft][52] = 40;
        nftApys[firstNft][60] = 40;
        nftApys[firstNft][61] = 40;
        nftApys[firstNft][62] = 40;
        nftApys[firstNft][63] = 40;
        nftApys[firstNft][64] = 40;
        nftApys[firstNft][65] = 40;
        nftApys[firstNft][66] = 40;
        nftApys[firstNft][67] = 40;
        // category 7(total 6)
        nftApys[firstNft][45] = 80;
        nftApys[firstNft][46] = 80;
        nftApys[firstNft][47] = 80;
        nftApys[firstNft][48] = 80;
        nftApys[firstNft][49] = 80;
        nftApys[firstNft][50] = 80;
        
        // second nft contract
        // category 4(total 1)
        nftApys[secondNft][1] = 20;
        // category 8(total 20)
        nftApys[secondNft][2] = 102;
        nftApys[secondNft][3] = 102;
        nftApys[secondNft][4] = 102;
        nftApys[secondNft][5] = 102;
        nftApys[secondNft][6] = 102;
        nftApys[secondNft][7] = 102;
        nftApys[secondNft][8] = 102;
        nftApys[secondNft][9] = 102;
        nftApys[secondNft][10] = 102;
        nftApys[secondNft][12] = 102;
        nftApys[secondNft][13] = 102;
        nftApys[secondNft][14] = 102;
        nftApys[secondNft][15] = 102;
        nftApys[secondNft][16] = 102;
        nftApys[secondNft][18] = 102;
        nftApys[secondNft][19] = 102;
        nftApys[secondNft][20] = 102;
        nftApys[secondNft][21] = 102;
        nftApys[secondNft][22] = 102;
        nftApys[secondNft][23] = 102;
    }

}

File 2 of 18 : ERC1155TokenReceiver.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.3;

import "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol";
import "./CommonConstants.sol";

abstract contract ERC1155TokenReceiver is ERC1155Receiver, CommonConstants {

    /**
     * ERC1155Receiver hook for single transfer.
     * @dev Reverts if the caller is not the whitelisted NFT contract.
     */
    function onERC1155Received(
        address, /*operator*/
        address, /*from _msgSender*/
        uint256, /*id*/
        uint256, /*value*/
        bytes calldata /*data*/
    ) external virtual override returns (bytes4) {
        return ERC1155_ACCEPTED;
    }

    /**
     * ERC1155Receiver hook for batch transfer.
     * @dev Reverts if the caller is not the whitelisted NFT contract.
     */
    function onERC1155BatchReceived(
        address, /*operator*/
        address, /*from*/
        uint256[] calldata, /*ids*/
        uint256[] calldata, /*value*/
        bytes calldata /*data*/
    ) external virtual override returns (bytes4) {
        return ERC1155_BATCH_ACCEPTED;
    }
}

File 3 of 18 : CommonConstants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;

/**
    Note: Simple contract to use as base for const vals
*/
contract CommonConstants {

    bytes4 constant internal ERC1155_ACCEPTED = 0xf23a6e61; // bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))
    bytes4 constant internal ERC1155_BATCH_ACCEPTED = 0xbc197c81; // bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))
}

File 4 of 18 : ABDKMath64x64.sol
// SPDX-License-Identifier: BSD-4-Clause
/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */
pragma solidity ^0.8.0;

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
  /*
   * Minimum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

  /*
   * Maximum value signed 64.64-bit fixed point number may have. 
   */
  int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

  /**
   * Convert signed 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromInt (int256 x) internal pure returns (int128) {
    unchecked {
      require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (x << 64);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 64-bit integer number
   * rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64-bit integer number
   */
  function toInt (int128 x) internal pure returns (int64) {
    unchecked {
      return int64 (x >> 64);
    }
  }

  /**
   * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
   * number.  Revert on overflow.
   *
   * @param x unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function fromUInt (uint256 x) internal pure returns (int128) {
    unchecked {
      require (x <= 0x7FFFFFFFFFFFFFFF);
      return int128 (int256 (x << 64));
    }
  }

  /**
   * Convert signed 64.64 fixed point number into unsigned 64-bit integer
   * number rounding down.  Revert on underflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return unsigned 64-bit integer number
   */
  function toUInt (int128 x) internal pure returns (uint64) {
    unchecked {
      require (x >= 0);
      return uint64 (uint128 (x >> 64));
    }
  }

  /**
   * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
   * number rounding down.  Revert on overflow.
   *
   * @param x signed 128.128-bin fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function from128x128 (int256 x) internal pure returns (int128) {
    unchecked {
      int256 result = x >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Convert signed 64.64 fixed point number into signed 128.128 fixed point
   * number.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 128.128 fixed point number
   */
  function to128x128 (int128 x) internal pure returns (int256) {
    unchecked {
      return int256 (x) << 64;
    }
  }

  /**
   * Calculate x + y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function add (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) + y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x - y.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sub (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) - y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding down.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function mul (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 result = int256(x) * y >> 64;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
   * number and y is signed 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y signed 256-bit integer number
   * @return signed 256-bit integer number
   */
  function muli (int128 x, int256 y) internal pure returns (int256) {
    unchecked {
      if (x == MIN_64x64) {
        require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF &&
          y <= 0x1000000000000000000000000000000000000000000000000);
        return -y << 63;
      } else {
        bool negativeResult = false;
        if (x < 0) {
          x = -x;
          negativeResult = true;
        }
        if (y < 0) {
          y = -y; // We rely on overflow behavior here
          negativeResult = !negativeResult;
        }
        uint256 absoluteResult = mulu (x, uint256 (y));
        if (negativeResult) {
          require (absoluteResult <=
            0x8000000000000000000000000000000000000000000000000000000000000000);
          return -int256 (absoluteResult); // We rely on overflow behavior here
        } else {
          require (absoluteResult <=
            0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
          return int256 (absoluteResult);
        }
      }
    }
  }

  /**
   * Calculate x * y rounding down, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64 fixed point number
   * @param y unsigned 256-bit integer number
   * @return unsigned 256-bit integer number
   */
  function mulu (int128 x, uint256 y) internal pure returns (uint256) {
    unchecked {
      if (y == 0) return 0;

      require (x >= 0);

      uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
      uint256 hi = uint256 (int256 (x)) * (y >> 128);

      require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      hi <<= 64;

      require (hi <=
        0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
      return hi + lo;
    }
  }

  /**
   * Calculate x / y rounding towards zero.  Revert on overflow or when y is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function div (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      int256 result = (int256 (x) << 64) / y;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are signed 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x signed 256-bit integer number
   * @param y signed 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divi (int256 x, int256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);

      bool negativeResult = false;
      if (x < 0) {
        x = -x; // We rely on overflow behavior here
        negativeResult = true;
      }
      if (y < 0) {
        y = -y; // We rely on overflow behavior here
        negativeResult = !negativeResult;
      }
      uint128 absoluteResult = divuu (uint256 (x), uint256 (y));
      if (negativeResult) {
        require (absoluteResult <= 0x80000000000000000000000000000000);
        return -int128 (absoluteResult); // We rely on overflow behavior here
      } else {
        require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
        return int128 (absoluteResult); // We rely on overflow behavior here
      }
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return signed 64.64-bit fixed point number
   */
  function divu (uint256 x, uint256 y) internal pure returns (int128) {
    unchecked {
      require (y != 0);
      uint128 result = divuu (x, y);
      require (result <= uint128 (MAX_64x64));
      return int128 (result);
    }
  }

  /**
   * Calculate -x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function neg (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return -x;
    }
  }

  /**
   * Calculate |x|.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function abs (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != MIN_64x64);
      return x < 0 ? -x : x;
    }
  }

  /**
   * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
   * zero.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function inv (int128 x) internal pure returns (int128) {
    unchecked {
      require (x != 0);
      int256 result = int256 (0x100000000000000000000000000000000) / x;
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function avg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      return int128 ((int256 (x) + int256 (y)) >> 1);
    }
  }

  /**
   * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
   * Revert on overflow or in case x * y is negative.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function gavg (int128 x, int128 y) internal pure returns (int128) {
    unchecked {
      int256 m = int256 (x) * int256 (y);
      require (m >= 0);
      require (m <
          0x4000000000000000000000000000000000000000000000000000000000000000);
      return int128 (sqrtu (uint256 (m)));
    }
  }

  /**
   * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
   * and y is unsigned 256-bit integer number.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @param y uint256 value
   * @return signed 64.64-bit fixed point number
   */
  function pow (int128 x, uint256 y) internal pure returns (int128) {
    unchecked {
      bool negative = x < 0 && y & 1 == 1;

      uint256 absX = uint128 (x < 0 ? -x : x);
      uint256 absResult;
      absResult = 0x100000000000000000000000000000000;

      if (absX <= 0x10000000000000000) {
        absX <<= 63;
        while (y != 0) {
          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x2 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x4 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          if (y & 0x8 != 0) {
            absResult = absResult * absX >> 127;
          }
          absX = absX * absX >> 127;

          y >>= 4;
        }

        absResult >>= 64;
      } else {
        uint256 absXShift = 63;
        if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; }
        if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; }
        if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; }
        if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; }
        if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; }
        if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; }

        uint256 resultShift = 0;
        while (y != 0) {
          require (absXShift < 64);

          if (y & 0x1 != 0) {
            absResult = absResult * absX >> 127;
            resultShift += absXShift;
            if (absResult > 0x100000000000000000000000000000000) {
              absResult >>= 1;
              resultShift += 1;
            }
          }
          absX = absX * absX >> 127;
          absXShift <<= 1;
          if (absX >= 0x100000000000000000000000000000000) {
              absX >>= 1;
              absXShift += 1;
          }

          y >>= 1;
        }

        require (resultShift < 64);
        absResult >>= 64 - resultShift;
      }
      int256 result = negative ? -int256 (absResult) : int256 (absResult);
      require (result >= MIN_64x64 && result <= MAX_64x64);
      return int128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down.  Revert if x < 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function sqrt (int128 x) internal pure returns (int128) {
    unchecked {
      require (x >= 0);
      return int128 (sqrtu (uint256 (int256 (x)) << 64));
    }
  }

  /**
   * Calculate binary logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function log_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      int256 msb = 0;
      int256 xc = x;
      if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; }
      if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
      if (xc >= 0x10000) { xc >>= 16; msb += 16; }
      if (xc >= 0x100) { xc >>= 8; msb += 8; }
      if (xc >= 0x10) { xc >>= 4; msb += 4; }
      if (xc >= 0x4) { xc >>= 2; msb += 2; }
      if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

      int256 result = msb - 64 << 64;
      uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb);
      for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
        ux *= ux;
        uint256 b = ux >> 255;
        ux >>= 127 + b;
        result += bit * int256 (b);
      }

      return int128 (result);
    }
  }

  /**
   * Calculate natural logarithm of x.  Revert if x <= 0.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function ln (int128 x) internal pure returns (int128) {
    unchecked {
      require (x > 0);

      return int128 (int256 (
          uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));
    }
  }

  /**
   * Calculate binary exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp_2 (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      uint256 result = 0x80000000000000000000000000000000;

      if (x & 0x8000000000000000 > 0)
        result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
      if (x & 0x4000000000000000 > 0)
        result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
      if (x & 0x2000000000000000 > 0)
        result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
      if (x & 0x1000000000000000 > 0)
        result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
      if (x & 0x800000000000000 > 0)
        result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
      if (x & 0x400000000000000 > 0)
        result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
      if (x & 0x200000000000000 > 0)
        result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
      if (x & 0x100000000000000 > 0)
        result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
      if (x & 0x80000000000000 > 0)
        result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
      if (x & 0x40000000000000 > 0)
        result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
      if (x & 0x20000000000000 > 0)
        result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
      if (x & 0x10000000000000 > 0)
        result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
      if (x & 0x8000000000000 > 0)
        result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
      if (x & 0x4000000000000 > 0)
        result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
      if (x & 0x2000000000000 > 0)
        result = result * 0x1000162E525EE054754457D5995292026 >> 128;
      if (x & 0x1000000000000 > 0)
        result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
      if (x & 0x800000000000 > 0)
        result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
      if (x & 0x400000000000 > 0)
        result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
      if (x & 0x200000000000 > 0)
        result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
      if (x & 0x100000000000 > 0)
        result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
      if (x & 0x80000000000 > 0)
        result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
      if (x & 0x40000000000 > 0)
        result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
      if (x & 0x20000000000 > 0)
        result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
      if (x & 0x10000000000 > 0)
        result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
      if (x & 0x8000000000 > 0)
        result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
      if (x & 0x4000000000 > 0)
        result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
      if (x & 0x2000000000 > 0)
        result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
      if (x & 0x1000000000 > 0)
        result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
      if (x & 0x800000000 > 0)
        result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
      if (x & 0x400000000 > 0)
        result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
      if (x & 0x200000000 > 0)
        result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
      if (x & 0x100000000 > 0)
        result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
      if (x & 0x80000000 > 0)
        result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
      if (x & 0x40000000 > 0)
        result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
      if (x & 0x20000000 > 0)
        result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
      if (x & 0x10000000 > 0)
        result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
      if (x & 0x8000000 > 0)
        result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
      if (x & 0x4000000 > 0)
        result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
      if (x & 0x2000000 > 0)
        result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
      if (x & 0x1000000 > 0)
        result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
      if (x & 0x800000 > 0)
        result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
      if (x & 0x400000 > 0)
        result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
      if (x & 0x200000 > 0)
        result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
      if (x & 0x100000 > 0)
        result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
      if (x & 0x80000 > 0)
        result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
      if (x & 0x40000 > 0)
        result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
      if (x & 0x20000 > 0)
        result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
      if (x & 0x10000 > 0)
        result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
      if (x & 0x8000 > 0)
        result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
      if (x & 0x4000 > 0)
        result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
      if (x & 0x2000 > 0)
        result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
      if (x & 0x1000 > 0)
        result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
      if (x & 0x800 > 0)
        result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
      if (x & 0x400 > 0)
        result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
      if (x & 0x200 > 0)
        result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
      if (x & 0x100 > 0)
        result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
      if (x & 0x80 > 0)
        result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
      if (x & 0x40 > 0)
        result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
      if (x & 0x20 > 0)
        result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
      if (x & 0x10 > 0)
        result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
      if (x & 0x8 > 0)
        result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
      if (x & 0x4 > 0)
        result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
      if (x & 0x2 > 0)
        result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
      if (x & 0x1 > 0)
        result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;

      result >>= uint256 (int256 (63 - (x >> 64)));
      require (result <= uint256 (int256 (MAX_64x64)));

      return int128 (int256 (result));
    }
  }

  /**
   * Calculate natural exponent of x.  Revert on overflow.
   *
   * @param x signed 64.64-bit fixed point number
   * @return signed 64.64-bit fixed point number
   */
  function exp (int128 x) internal pure returns (int128) {
    unchecked {
      require (x < 0x400000000000000000); // Overflow

      if (x < -0x400000000000000000) return 0; // Underflow

      return exp_2 (
          int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
    }
  }

  /**
   * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
   * integer numbers.  Revert on overflow or when y is zero.
   *
   * @param x unsigned 256-bit integer number
   * @param y unsigned 256-bit integer number
   * @return unsigned 64.64-bit fixed point number
   */
  function divuu (uint256 x, uint256 y) private pure returns (uint128) {
    unchecked {
      require (y != 0);

      uint256 result;

      if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        result = (x << 64) / y;
      else {
        uint256 msb = 192;
        uint256 xc = x >> 192;
        if (xc >= 0x100000000) { xc >>= 32; msb += 32; }
        if (xc >= 0x10000) { xc >>= 16; msb += 16; }
        if (xc >= 0x100) { xc >>= 8; msb += 8; }
        if (xc >= 0x10) { xc >>= 4; msb += 4; }
        if (xc >= 0x4) { xc >>= 2; msb += 2; }
        if (xc >= 0x2) msb += 1;  // No need to shift xc anymore

        result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
        require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 hi = result * (y >> 128);
        uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

        uint256 xh = x >> 192;
        uint256 xl = x << 64;

        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here
        lo = hi << 128;
        if (xl < lo) xh -= 1;
        xl -= lo; // We rely on overflow behavior here

        assert (xh == hi >> 128);

        result += xl / y;
      }

      require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
      return uint128 (result);
    }
  }

  /**
   * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
   * number.
   *
   * @param x unsigned 256-bit integer number
   * @return unsigned 128-bit integer number
   */
  function sqrtu (uint256 x) private pure returns (uint128) {
    unchecked {
      if (x == 0) return 0;
      else {
        uint256 xx = x;
        uint256 r = 1;
        if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; }
        if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; }
        if (xx >= 0x100000000) { xx >>= 32; r <<= 16; }
        if (xx >= 0x10000) { xx >>= 16; r <<= 8; }
        if (xx >= 0x100) { xx >>= 8; r <<= 4; }
        if (xx >= 0x10) { xx >>= 4; r <<= 2; }
        if (xx >= 0x8) { r <<= 1; }
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1;
        r = (r + x / r) >> 1; // Seven iterations should be enough
        uint256 r1 = x / r;
        return uint128 (r < r1 ? r : r1);
      }
    }
  }
}

File 5 of 18 : IUniswapV2Pair.sol
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.3;

interface IUniswapV2Pair {
    event Approval(address indexed owner, address indexed spender, uint value);
    event Transfer(address indexed from, address indexed to, uint value);

    function name() external pure returns (string memory);
    function symbol() external pure returns (string memory);
    function decimals() external pure returns (uint8);
    function totalSupply() external view returns (uint);
    function balanceOf(address owner) external view returns (uint);
    function allowance(address owner, address spender) external view returns (uint);

    function approve(address spender, uint value) external returns (bool);
    function transfer(address to, uint value) external returns (bool);
    function transferFrom(address from, address to, uint value) external returns (bool);

    function DOMAIN_SEPARATOR() external view returns (bytes32);
    function PERMIT_TYPEHASH() external pure returns (bytes32);
    function nonces(address owner) external view returns (uint);

    function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;

    event Mint(address indexed sender, uint amount0, uint amount1);
    event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
    event Swap(
        address indexed sender,
        uint amount0In,
        uint amount1In,
        uint amount0Out,
        uint amount1Out,
        address indexed to
    );
    event Sync(uint112 reserve0, uint112 reserve1);

    function MINIMUM_LIQUIDITY() external pure returns (uint);
    function factory() external view returns (address);
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
    function price0CumulativeLast() external view returns (uint);
    function price1CumulativeLast() external view returns (uint);
    function kLast() external view returns (uint);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
    function skim(address to) external;
    function sync() external;

    function initialize(address, address) external;
}

File 6 of 18 : ERC20Interface.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.3;

interface ERC20Interface {
    function transfer(address _to, uint256 _value) external returns (bool);
    function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
    function balanceOf(address _account) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function allowance(address tokenOwner, address spender) external view returns (uint remaining);
    function approve(address spender, uint tokens) external returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}

File 7 of 18 : Calculator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
import "./abdk-libraries/ABDKMath64x64.sol";

/**
 * Tools for calculating rewards.
 * Calculation formula: F=P*(1+i)^n
 */
library Calculator {
    /*
     * calculate rewards
     * steps
     * 1. Calculate rewards by apy
     * 2. Get principal and rewards
     * @param principal principal amount
     * @param n periods for calculating interest,  one second eq to one period
     * @param apy annual percentage yield
     * @return sum of principal and rewards
     */
  function calculator(
        uint256 principal,
        uint256 n,
        uint256 apy
   ) internal pure returns (uint256 amount) {
        int128 div = ABDKMath64x64.divu(apy, 36500 * 1 days); // second rate
        int128 sum = ABDKMath64x64.add(ABDKMath64x64.fromInt(1), div);
        int128 pow = ABDKMath64x64.pow(sum, n);
        uint256 res = ABDKMath64x64.mulu(pow, principal);
        return res;
    }

  function getValueOfRepresentUmi(
      uint256 stakedLpTokens,
      uint256 lpTokenTotalSupply,
      uint112 umiReserve) internal pure returns(uint256) {
      int128 lpRatio = ABDKMath64x64.divu(stakedLpTokens, lpTokenTotalSupply);
      uint256 res = ABDKMath64x64.mulu(lpRatio, uint256(umiReserve));
      return res;
  }

}

File 8 of 18 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 9 of 18 : IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * 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);
}

File 10 of 18 : ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./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;
    }
}

File 11 of 18 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

File 12 of 18 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 13 of 18 : ERC1155Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC1155Receiver.sol";
import "../../../utils/introspection/ERC165.sol";

/**
 * @dev _Available since v3.1._
 */
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
    }
}

File 14 of 18 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
        @dev Handles the receipt of a single ERC1155 token type. This function is
        called at the end of a `safeTransferFrom` after the balance has been updated.
        To accept the transfer, this must return
        `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
        (i.e. 0xf23a6e61, or its own function selector).
        @param operator The address which initiated the transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param id The ID of the token being transferred
        @param value The amount of tokens being transferred
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
    */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
        @dev Handles the receipt of a multiple ERC1155 token types. This function
        is called at the end of a `safeBatchTransferFrom` after the balances have
        been updated. To accept the transfer(s), this must return
        `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
        (i.e. 0xbc197c81, or its own function selector).
        @param operator The address which initiated the batch transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param ids An array containing ids of each token being transferred (order and length must match values array)
        @param values An array containing amounts of each token being transferred (order and length must match ids array)
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
    */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 15 of 18 : IERC1155.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 16 of 18 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

File 17 of 18 : Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 18 of 18 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _setOwner(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _setOwner(address(0));
    }

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

    function _setOwner(address newOwner) private {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

Settings
{
  "remappings": [],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_umiAddress","type":"address"},{"internalType":"address","name":"_lpAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"BaseApySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"principal","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"interest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"claimTimestamp","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"ContractFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"NftApySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"NftStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"NftUnstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"NftsBatchStaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"nftAddress","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"nftIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"NftsBatchUnstaked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"apy","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"umiInterest","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timePassed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"BASE_APY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"batchStakeNfts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"batchUnstakeNfts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"}],"name":"calculateUmiTokenRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"funding","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"fundingContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getLpBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getNftBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getTotalApyOfUser","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getUmiBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"}],"name":"getUserNftIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"}],"name":"getUserNftIdsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"isInWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"isNftIdExist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isNftSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpToken","outputs":[{"internalType":"contract IUniswapV2Pair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftAddresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftApys","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"nftBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint8","name":"apy","type":"uint8"}],"name":"setApyByTokenId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_APY","type":"uint256"}],"name":"setBaseApy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakeDates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"stakeNft","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFunding","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalNftStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"umiToken","outputs":[{"internalType":"contract ERC20Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"unstakeNft","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6080604052600f80546001600160a01b031990811673d194f079cc291fe9db7dad95444eec124641363617909155601080549091167390ad78735bc59a5dcb6a038728684c484cd5860d17905560216011553480156200005e57600080fd5b5060405162005b8038038062005b8083398101604081905262000081916200225e565b6200008c3362000214565b600180556002805460ff19169055620000ba6001600160a01b03831662000264602090811b620016bc17901c565b8015620000e15750620000e1816001600160a01b03166200026460201b620016bc1760201c565b620001335760405162461bcd60e51b815260206004820152601960248201527f6d7573742075736520636f6e747261637420616464726573730000000000000060448201526064015b60405180910390fd5b600380546001600160a01b038085166001600160a01b0319928316179092556002805484841661010002610100600160a81b0319909116179055600f8054600d8054600181810183557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5918201805487169488169490941790935560108054835480860190945592909101805490951691861691909117909355905483166000908152600e6020526040808220805460ff1990811685179091559354909416815292909220805490911690911790556200020c6200026e565b505062002295565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b803b15155b919050565b6000546001600160a01b03163314620002ca5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200012a565b600160096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000603b815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600260096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006012815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600260096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006013815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600260096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006014815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006001815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006002815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006004815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006005815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006006815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006007815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006008815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006009815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600c815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600d815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600e815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600f815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006010815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006016815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006017815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006018815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000601a815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000601b815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000601c815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000601d815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000601e815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000601f815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006020815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006021815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006023815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006024815260200190815260200160002060006101000a81548160ff021916908360ff160217905550600a60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006025815260200190815260200160002060006101000a81548160ff021916908360ff160217905550601460096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006003815260200190815260200160002060006101000a81548160ff021916908360ff160217905550601460096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600b815260200190815260200160002060006101000a81548160ff021916908360ff160217905550601460096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006019815260200190815260200160002060006101000a81548160ff021916908360ff160217905550601460096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006022815260200190815260200160002060006101000a81548160ff021916908360ff160217905550601e60096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006011815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006026815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006027815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006028815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006029815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000602a815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000602b815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000602c815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006034815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000603c815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000603d815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000603e815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000603f815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006040815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006041815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006042815260200190815260200160002060006101000a81548160ff021916908360ff160217905550602860096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006043815260200190815260200160002060006101000a81548160ff021916908360ff160217905550605060096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000602d815260200190815260200160002060006101000a81548160ff021916908360ff160217905550605060096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000602e815260200190815260200160002060006101000a81548160ff021916908360ff160217905550605060096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000602f815260200190815260200160002060006101000a81548160ff021916908360ff160217905550605060096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006030815260200190815260200160002060006101000a81548160ff021916908360ff160217905550605060096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006031815260200190815260200160002060006101000a81548160ff021916908360ff160217905550605060096000600f60009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006032815260200190815260200160002060006101000a81548160ff021916908360ff160217905550601460096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006001815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006002815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006003815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006004815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006005815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006006815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006007815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006008815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006009815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600a815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600c815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600d815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600e815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020019081526020016000206000600f815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006010815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006012815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006013815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006014815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006015815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006016815260200190815260200160002060006101000a81548160ff021916908360ff160217905550606660096000601060009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b0316815260200190815260200160002060006017815260200190815260200160002060006101000a81548160ff021916908360ff160217905550565b80516001600160a01b03811681146200026957600080fd5b6000806040838503121562002271578182fd5b6200227c8362002246565b91506200228c6020840162002246565b90509250929050565b6138db80620022a56000396000f3fe608060405234801561001057600080fd5b50600436106102535760003560e01c8063715018a611610146578063a694fc3a116100c3578063e6a027d111610087578063e6a027d1146105f1578063f23a6e6114610604578063f2fde38b14610624578063f686f76d14610637578063faaec8491461064a578063fe47a8a71461065357610253565b8063a694fc3a1461053c578063aa381fc61461054f578063adce53e114610562578063bc197c8114610585578063c27bec20146105c057610253565b80638da5cb5b1161010a5780638da5cb5b146104d25780639616d0b8146104e35780639b427368146104f65780639dcc36da14610509578063a1fe277c1461051c57610253565b8063715018a61461045d5780637b74a4d514610465578063817b1cd2146104785780638456cb59146104815780638cf070581461048957610253565b8063440d7c7a116101d45780635dcac841116101985780635dcac841146103d35780635fcbd285146103e657806369163daa146103fe5780636a93edaf146104115780636f784d6b1461044a57610253565b8063440d7c7a14610391578063447d4ea9146103a45780634ca19fd6146103b75780634e71d92d146103c05780635c975abb146103c857610253565b806325280d541161021b57806325280d541461032e57806327e235e31461034e5780632def66201461036e57806339dc50f5146103765780633f4ba83a1461038957610253565b806301ffc9a714610258578063049f2d8a146102805780631d3c5b0e146102ae578063241b4a2d146102ee57806324ec5a7814610303575b600080fd5b61026b610266366004613495565b61065c565b60405190151581526020015b60405180910390f35b6102a061028e366004613147565b60076020526000908152604090205481565b604051908152602001610277565b6102dc6102bc3660046133a2565b600960209081526000928352604080842090915290825290205460ff1681565b60405160ff9091168152602001610277565b6103016102fc3660046133cb565b610695565b005b610316610311366004613500565b610701565b6040516001600160a01b039091168152602001610277565b6102a061033c366004613147565b60056020526000908152604090205481565b6102a061035c366004613147565b60046020526000908152604090205481565b61030161072b565b6102a0610384366004613147565b610785565b610301610801565b61026b61039f3660046133a2565b610835565b6103016103b23660046132fb565b610865565b6102a060115481565b610301610980565b60025460ff1661026b565b6103016103e1366004613500565b610c6c565b6002546103169061010090046001600160a01b031681565b61030161040c3660046132fb565b610e2a565b6102a061041f366004613161565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205490565b6102a061045836600461324a565b610ed5565b610301610f60565b6102a0610473366004613147565b610f94565b6102a060065481565b610301611179565b61026b61049736600461324a565b6001600160a01b038084166000908152600b6020908152604080832093861683529281528282208483526001019052205460ff169392505050565b6000546001600160a01b0316610316565b6102a06104f1366004613147565b6111ab565b610301610504366004613500565b61122a565b6103016105173660046133cb565b611294565b61052f61052a366004613161565b61134e565b6040516102779190613701565b61030161054a366004613500565b6113c7565b6102a061055d366004613147565b611423565b61026b610570366004613147565b600e6020526000908152604090205460ff1681565b6105a7610593366004613193565b63bc197c8160e01b98975050505050505050565b6040516001600160e01b03199091168152602001610277565b6102a06105ce36600461324a565b600a60209081526000938452604080852082529284528284209052825290205481565b6103016105ff366004613431565b61145b565b6105a7610612366004613285565b63f23a6e6160e01b9695505050505050565b610301610632366004613147565b611621565b600354610316906001600160a01b031681565b6102a0600c5481565b6102a060085481565b60006001600160e01b03198216630271189760e51b148061068d57506301ffc9a760e01b6001600160e01b03198316145b90505b919050565b60025460ff16156106c15760405162461bcd60e51b81526004016106b890613790565b60405180910390fd5b600260015414156106e45760405162461bcd60e51b81526004016106b8906137ef565b60026001556106f685858585856116c2565b505060018055505050565b600d818154811061071157600080fd5b6000918252602090912001546001600160a01b0316905081565b60025460ff161561074e5760405162461bcd60e51b81526004016106b890613790565b600260015414156107715760405162461bcd60e51b81526004016106b8906137ef565b600260015561077f336118ba565b60018055565b6001600160a01b038116600090815260046020526040812054806107ad576000915050610690565b60008060006107bd866000611c14565b9250925092506000831180156107d1575060015b6107ed5760405162461bcd60e51b81526004016106b89061374a565b6107f78383611dd9565b9695505050505050565b6000546001600160a01b0316331461082b5760405162461bcd60e51b81526004016106b8906137ba565b610833611dec565b565b6001600160a01b038216600090815260096020908152604080832084845290915290205460ff1615155b92915050565b60025460ff16156108885760405162461bcd60e51b81526004016106b890613790565b600260015414156108ab5760405162461bcd60e51b81526004016106b8906137ef565b60026001558483146108ff5760405162461bcd60e51b815260206004820152601e60248201527f69647320616e642076616c756573206c656e677468206d69736d61746368000060448201526064016106b8565b61097333308989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152508a9250899150611e7f9050565b5050600180555050505050565b60025460ff16156109a35760405162461bcd60e51b81526004016106b890613790565b600260015414156109c65760405162461bcd60e51b81526004016106b8906137ef565b60026001553360009081526004602052604090205480610a285760405162461bcd60e51b815260206004820152601a60248201527f62616c616e63652073686f756c64206d6f7265207468616e203000000000000060448201526064016106b8565b6000806000610a38336000611c14565b925092509250600083118015610a4c575060015b610a685760405162461bcd60e51b81526004016106b89061374a565b6000610a748484611dd9565b905060008111610ac65760405162461bcd60e51b815260206004820152601f60248201527f636c61696d20696e746572657374206d757374206d6f7265207468616e20300060448201526064016106b8565b806008541015610b295760405162461bcd60e51b815260206004820152602860248201527f746f74616c2066756e64696e67206e6f7420656e6f75676820746f20706179206044820152671a5b9d195c995cdd60c21b60648201526084016106b8565b600854610b369082611dd9565b6008556000423360008181526005602052604090819020839055600354905163a9059cbb60e01b81526004810192909252602482018590529192506001600160a01b039091169063a9059cbb90604401602060405180830381600087803b158015610ba057600080fd5b505af1158015610bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd89190613475565b610c1d5760405162461bcd60e51b815260206004820152601660248201527518db185a5b4e881d1c985b9cd9995c8819985a5b195960521b60448201526064016106b8565b604080518781526020810184905290810182905233907f9cdcf2f7714cca3508c7f0110b04a90a80a3a8dd0e35de99689db74d28c5383e9060600160405180910390a250506001805550505050565b60026001541415610c8f5760405162461bcd60e51b81526004016106b8906137ef565b600260015580610ce15760405162461bcd60e51b815260206004820152601d60248201527f5f616d6f756e742073686f756c64206265206d6f7265207468616e203000000060448201526064016106b8565b3360009081526007602052604081208054839290610d00908490613826565b925050819055508060086000828254610d199190613826565b90915550506003546040516323b872dd60e01b8152336004820152306024820152604481018390526001600160a01b03909116906323b872dd90606401602060405180830381600087803b158015610d7057600080fd5b505af1158015610d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da89190613475565b610dea5760405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b60448201526064016106b8565b60408051828152426020820152815133927f3b31cbadfd3fd939750f09d3bdbd6c0531dde23f05d55dcc202798f39d090895928290030190a25060018055565b60025460ff1615610e4d5760405162461bcd60e51b81526004016106b890613790565b60026001541415610e705760405162461bcd60e51b81526004016106b8906137ef565b6002600155848314610ec45760405162461bcd60e51b815260206004820152601e60248201527f69647320616e642076616c756573206c656e677468206d69736d61746368000060448201526064016106b8565b6109733033898989898989896120ef565b600082604051627eeac760e11b81526001600160a01b03868116600483015260248201859052919091169062fdd58e9060440160206040518083038186803b158015610f2057600080fd5b505afa158015610f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f589190613518565b949350505050565b6000546001600160a01b03163314610f8a5760405162461bcd60e51b81526004016106b8906137ba565b6108336000612429565b6001600160a01b03811660009081526004602052604081205480610fbc576000915050610690565b60115460005b600d5481101561117157600061100d86600d8481548110610ff357634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031661134e565b9050600081511161101e575061115f565b60005b815181101561115c57600082828151811061104c57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000600a60008a6001600160a01b03166001600160a01b031681526020019081526020016000206000600d87815481106110a057634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b031683528281019390935260409182018120858252909252812054600d8054919350600991839190899081106110fb57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168352828101939093526040918201812086825290925290205460ff16905061114461113d8383612479565b8890612485565b9650505050808061115490613874565b915050611021565b50505b8061116981613874565b915050610fc2565b509392505050565b6000546001600160a01b031633146111a35760405162461bcd60e51b81526004016106b8906137ba565b610833612491565b6003546040516370a0823160e01b81526001600160a01b03838116600483015260009216906370a08231906024015b60206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068d9190613518565b6000546001600160a01b031633146112545760405162461bcd60e51b81526004016106b8906137ba565b6011819055604080518281523360208201527f6766a9d3fdc5e039898b997749d240694539e82595bf4f16d66006f97431b126910160405180910390a150565b60025460ff16156112b75760405162461bcd60e51b81526004016106b890613790565b600260015414156112da5760405162461bcd60e51b81526004016106b8906137ef565b60026001556112e98585610835565b61133f5760405162461bcd60e51b815260206004820152602160248201527f7374616b654e66743a206e6674206964206e6f7420696e2077686974656c69736044820152601d60fa1b60648201526084016106b8565b6106f6333087878787876124e9565b6001600160a01b038083166000908152600b602090815260408083209385168352928152908290208054835181840281018401909452808452606093928301828280156113ba57602002820191906000526020600020905b8154815260200190600101908083116113a6575b5050505050905092915050565b60025460ff16156113ea5760405162461bcd60e51b81526004016106b890613790565b6002600154141561140d5760405162461bcd60e51b81526004016106b8906137ef565b600260015561141c3382612675565b5060018055565b6002546040516370a0823160e01b81526001600160a01b038381166004830152600092610100900416906370a08231906024016111da565b6000546001600160a01b031633146114855760405162461bcd60e51b81526004016106b8906137ba565b6001600160a01b0383166114d35760405162461bcd60e51b81526020600482015260156024820152741b999d081859191c995cdcc81a5b98dbdc9c9958dd605a1b60448201526064016106b8565b6000821180156114e6575060008160ff16115b6115295760405162461bcd60e51b815260206004820152601460248201527306e667420616e6420617079206d757374203e20360641b60448201526064016106b8565b6001600160a01b0383166000908152600e602052604090205460ff166115ad57600d805460018082019092557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0386169081179091556000908152600e60205260409020805460ff191690911790555b6001600160a01b0383166000818152600960209081526040808320868452825291829020805460ff861660ff199091168117909155825186815291820152338183015290517f5e244736b7eeb9972c03e5b93e7d50f2509b03864d8aa9f1339adeef0a7d24639181900360600190a2505050565b6000546001600160a01b0316331461164b5760405162461bcd60e51b81526004016106b8906137ba565b6001600160a01b0381166116b05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106b8565b6116b981612429565b50565b3b151590565b60006116cd33610785565b336000908152600460205260409020549091506116eb5760006116ed565b425b33600090815260056020908152604080832093909355600a81528282206001600160a01b038a168352815282822088835290522054848110156117725760405162461bcd60e51b815260206004820181905260248201527f696e73756666696369656e742062616c616e636520666f7220756e7374616b6560448201526064016106b8565b61177c8186611dd9565b336000908152600a602090815260408083206001600160a01b038c16845282528083208a8452909152902055600c546117b59086611dd9565b600c55336000908152600a602090815260408083206001600160a01b038b16845282528083208984529091529020546117f2576117f28787612863565b604051637921219560e11b81526001600160a01b0388169063f242432a9061182890309033908b908b908b908b9060040161368c565b600060405180830381600087803b15801561184257600080fd5b505af1158015611856573d6000803e3d6000fd5b5050505061186433836129f7565b6001600160a01b038716337f5a62b64705b9e7c31cb4c877f4cf7d9b38a6c01cd0e00e76c8f43a03becc02348888426040805193845260208401929092529082015260600160405180910390a350505050505050565b336000908152600460205260409020548061190c5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b60448201526064016106b8565b600080600061191c856000611c14565b9250925092506000831180156119325750600081115b61198c5760405162461bcd60e51b815260206004820152602560248201527f746f74616c57697468496e7465726573743c3d30206f722074696d6550617373604482015264065643c3d360dc1b60648201526084016106b8565b6001600160a01b038516600090815260046020908152604080832083905560059091528120556006546119bf9085611dd9565b60065560006119ce8484611dd9565b9050600080821180156119e357508160085410155b156119fc575060085481906119f89082611dd9565b6008555b8015611ad45760035460405163a9059cbb60e01b81526001600160a01b038981166004830152602482018490529091169063a9059cbb90604401602060405180830381600087803b158015611a5057600080fd5b505af1158015611a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a889190613475565b611ad45760405162461bcd60e51b815260206004820152601c60248201527f5f756e7374616b6520756d69207472616e73666572206661696c65640000000060448201526064016106b8565b60025460405163a9059cbb60e01b81526001600160a01b038981166004830152602482018990526101009092049091169063a9059cbb90604401602060405180830381600087803b158015611b2857600080fd5b505af1158015611b3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b609190613475565b611bac5760405162461bcd60e51b815260206004820152601c60248201527f5f756e7374616b653a206c70207472616e73666572206661696c65640000000060448201526064016106b8565b866001600160a01b03167f055f388d8102e9e2bfeaa944b25b4cdb0c06fd1c42d5c2812a8f3c7ac1aa26d3611be089610f94565b60408051918252602082018a905281810185905260608201879052426080830152519081900360a00190a250505050505050565b6001600160a01b03821660009081526004602052604081205481908190818515611c3e5785611c40565b815b6001600160a01b038816600090815260056020526040812054919250611c664283611dd9565b90506001811015611c8357600096508695509350611dd292505050565b6000611c8e8a610f94565b90506000600260019054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ce057600080fd5b505afa158015611cf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d189190613518565b90506000600260019054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611d6a57600080fd5b505afa158015611d7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da291906134bd565b505090506000611db3878484612aea565b90506000611dc2828787612b0e565b9b50909950939750505050505050505b9250925092565b6000611de5828461385d565b9392505050565b60025460ff16611e355760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016106b8565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000611e8a88610785565b6001600160a01b038916600090815260046020526040902054909150611eb1576000611eb3565b425b6001600160a01b0389166000908152600560205260408120919091555b855181101561201d576000868281518110611efb57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000868381518110611f2757634e487b7160e01b600052603260045260246000fd5b60200260200101519050611f3b8983610835565b611f875760405162461bcd60e51b815260206004820152601760248201527f6e6674206964206e6f7420696e2077686974656c69737400000000000000000060448201526064016106b8565b6001600160a01b03808c166000908152600a60209081526040808320938d16835292815282822085835290522054611fbf9082612485565b6001600160a01b03808d166000908152600a60209081526040808320938e16835292815282822086835290522055611ff88b8a84612b5e565b600c546120059082612485565b600c555081905061201581613874565b915050611ed0565b50604051631759616b60e11b81526001600160a01b03871690632eb2c2d690612054908b908b908a908a908a908a9060040161362c565b600060405180830381600087803b15801561206e57600080fd5b505af1158015612082573d6000803e3d6000fd5b5050505061209033826129f7565b856001600160a01b0316886001600160a01b03167fc2f970af6b072882b84bbf83c8fc68080b10e5847ab197c629e18c0ad406d39287876120ce4290565b6040516120dd93929190613714565b60405180910390a35050505050505050565b60006120fa8a610785565b6001600160a01b038b16600090815260046020526040902054909150612121576000612123565b425b6001600160a01b038b166000908152600560205260408120919091555b8681101561235c57600088888381811061216a57634e487b7160e01b600052603260045260246000fd5b905060200201359050600087878481811061219557634e487b7160e01b600052603260045260246000fd5b9050602002013590506000600a6000336001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b031681526020019081526020016000206000848152602001908152602001600020549050818110156122585760405162461bcd60e51b8152602060048201526024808201527f696e73756666696369656e74206e66742062616c616e636520666f7220756e7360448201526374616b6560e01b60648201526084016106b8565b6122628183611dd9565b600a6000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b031681526020019081526020016000206000858152602001908152602001600020819055506122d482600c54611dd990919063ffffffff16565b600c81905550600a6000336001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b0316815260200190815260200160002060008481526020019081526020016000205460001415612346576123468c84612863565b505050808061235490613874565b915050612140565b50604051631759616b60e11b81526001600160a01b03891690632eb2c2d690612397908d908d908c908c908c908c908c908c906004016135c8565b600060405180830381600087803b1580156123b157600080fd5b505af11580156123c5573d6000803e3d6000fd5b505050506123d333826129f7565b6001600160a01b038816337f77455a41e4b718cead56169d2fdc4d2de52ca373c87aca655f14d5131e19941089898989426040516124159594939291906136c7565b60405180910390a350505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000611de5828461383e565b6000611de58284613826565b60025460ff16156124b45760405162461bcd60e51b81526004016106b890613790565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611e623390565b60006124f488610785565b6001600160a01b03891660009081526004602052604090205490915061251b57600061251d565b425b6001600160a01b03808a16600090815260056020908152604080832094909455600a8152838220928a16825291825282812088825290915220546125619085612485565b6001600160a01b03808a166000908152600a60209081526040808320938b1683529281528282208983529052205561259a888787612b5e565b600c546125a79085612485565b600c55604051637921219560e11b81526001600160a01b0387169063f242432a906125e0908b908b908a908a908a908a9060040161368c565b600060405180830381600087803b1580156125fa57600080fd5b505af115801561260e573d6000803e3d6000fd5b5050505061261c88826129f7565b856001600160a01b0316886001600160a01b03167f04d24c87a9fd202d8e2c705a0d245fdd66387174bf8105618f4ecb0100ddf0e1878761265a4290565b604080519384526020840192909252908201526060016120dd565b600081116126d05760405162461bcd60e51b815260206004820152602260248201527f7374616b6520616d6f756e742073686f756c64206265206d6f7265207468616e604482015261020360f41b60648201526084016106b8565b60006126db83610785565b6001600160a01b0384166000908152600460205260409020549091506127019083612485565b6001600160a01b0384166000908152600460205260409020556006546127279083612485565b6006556001600160a01b0383166000818152600560209081526040918290204290819055825186815291820181905282519093927f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90928290030190a26002546040516323b872dd60e01b81526001600160a01b03868116600483015230602483015260448201869052610100909204909116906323b872dd90606401602060405180830381600087803b1580156127dd57600080fd5b505af11580156127f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128159190613475565b6128535760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016106b8565b61285d84836129f7565b50505050565b336000908152600b602090815260408083206001600160a01b038616845290915290208054819060018201906128ec5760405162461bcd60e51b815260206004820152602860248201527f72656d6f76652075736572206e6674206964732c20696473206c656e6774682060448201526706d757374203e20360c41b60648201526084016106b8565b60005b82548110156129ef578483828154811061291957634e487b7160e01b600052603260045260246000fd5b906000526020600020015414156129dd578254839061293a9060019061385d565b8154811061295857634e487b7160e01b600052603260045260246000fd5b906000526020600020015483828154811061298357634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101929092558681529083905260409020805460ff1916905582548390806129c657634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590555b806129e781613874565b9150506128ef565b505050505050565b60008111612a0457612ae6565b600854612a119082611dd9565b60085560035460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb90604401602060405180830381600087803b158015612a6257600080fd5b505af1158015612a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9a9190613475565b612ae65760405162461bcd60e51b815260206004820152601c60248201527f7472616e7366657220756d6920696e746572657374206661696c65640000000060448201526064016106b8565b5050565b600080612af78585612bd1565b905060006107f782856001600160701b0316612c08565b600080612b1f8363bbf81e00612bd1565b90506000612b36612b306001612c70565b83612ca3565b90506000612b448287612cd7565b90506000612b528289612c08565b98975050505050505050565b6001600160a01b038084166000908152600b6020908152604080832093861683529281528282208483526001810191829052929091205482919060ff166129ef57815460018082018455600093845260208085209092018690559483525260409020805460ff1916909217909155505050565b600081612bdd57600080fd5b6000612be98484612ef5565b905060016001607f1b036001600160801b0382161115611de557600080fd5b600081612c175750600061085f565b600083600f0b1215612c2857600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115612c5757600080fd5b60401b8119811115612c6857600080fd5b019392505050565b6000677fffffffffffffff198212158015612c935750677fffffffffffffff8213155b612c9c57600080fd5b5060401b90565b6000600f83810b9083900b0160016001607f1b03198112801590612cce575060016001607f1b038113155b611de557600080fd5b600080600084600f0b128015612cf05750826001166001145b905060008085600f0b12612d045784612d09565b846000035b6001600160801b03169050600160801b680100000000000000008211612da357603f82901b91505b8415612d9b576001851615612d46578102607f1c5b908002607f1c906002851615612d5c578102607f1c5b908002607f1c906004851615612d72578102607f1c5b908002607f1c906008851615612d88578102607f1c5b60049490941c93908002607f1c90612d31565b60401c612eb9565b603f600160601b831015612dbd5760209290921b91601f19015b600160701b831015612dd55760109290921b91600f19015b600160781b831015612ded5760089290921b91600719015b6001607c1b831015612e055760049290921b91600319015b6001607e1b831015612e1d5760029290921b91600119015b6001607f1b831015612e355760019290921b91600019015b60005b8615612ea25760408210612e4b57600080fd5b6001871615612e7157918302607f1c918101600160801b831115612e7157600192831c92015b928002607f1c9260019190911b90600160801b8410612e9657600193841c9391909101905b600187901c9650612e38565b60408110612eaf57600080fd5b6040039190911c90505b600083612ec65781612ecb565b816000035b905060016001607f1b03198112801590612eec575060016001607f1b038113155b6107f757600080fd5b600081612f0157600080fd5b60006001600160c01b038411612f3a5782604085901b81612f3257634e487b7160e01b600052601260045260246000fd5b04905061307b565b60c084811c6401000000008110612f53576020918201911c5b620100008110612f65576010918201911c5b6101008110612f76576008918201911c5b60108110612f86576004918201911c5b60048110612f96576002918201911c5b60028110612fa5576001820191505b60bf820360018603901c6001018260ff0387901b81612fd457634e487b7160e01b600052601260045260246000fd5b0492506001600160801b03831115612feb57600080fd5b608085901c83026001600160801b038616840260c088901c604089901b82811015613017576001820391505b608084901b9290038281101561302e576001820391505b829003608084901c821461305257634e487b7160e01b600052600160045260246000fd5b88818161306f57634e487b7160e01b600052601260045260246000fd5b04870196505050505050505b6001600160801b03811115611de557600080fd5b80356001600160a01b038116811461069057600080fd5b60008083601f8401126130b7578182fd5b50813567ffffffffffffffff8111156130ce578182fd5b6020830191508360208260051b85010111156130e957600080fd5b9250929050565b60008083601f840112613101578182fd5b50813567ffffffffffffffff811115613118578182fd5b6020830191508360208285010111156130e957600080fd5b80516001600160701b038116811461069057600080fd5b600060208284031215613158578081fd5b611de58261308f565b60008060408385031215613173578081fd5b61317c8361308f565b915061318a6020840161308f565b90509250929050565b60008060008060008060008060a0898b0312156131ae578384fd5b6131b78961308f565b97506131c560208a0161308f565b9650604089013567ffffffffffffffff808211156131e1578586fd5b6131ed8c838d016130a6565b909850965060608b0135915080821115613205578586fd5b6132118c838d016130a6565b909650945060808b0135915080821115613229578384fd5b506132368b828c016130f0565b999c989b5096995094979396929594505050565b60008060006060848603121561325e578283fd5b6132678461308f565b92506132756020850161308f565b9150604084013590509250925092565b60008060008060008060a0878903121561329d578182fd5b6132a68761308f565b95506132b46020880161308f565b94506040870135935060608701359250608087013567ffffffffffffffff8111156132dd578283fd5b6132e989828a016130f0565b979a9699509497509295939492505050565b60008060008060008060006080888a031215613315578283fd5b61331e8861308f565b9650602088013567ffffffffffffffff8082111561333a578485fd5b6133468b838c016130a6565b909850965060408a013591508082111561335e578485fd5b61336a8b838c016130a6565b909650945060608a0135915080821115613382578384fd5b5061338f8a828b016130f0565b989b979a50959850939692959293505050565b600080604083850312156133b4578182fd5b6133bd8361308f565b946020939093013593505050565b6000806000806000608086880312156133e2578081fd5b6133eb8661308f565b94506020860135935060408601359250606086013567ffffffffffffffff811115613414578182fd5b613420888289016130f0565b969995985093965092949392505050565b600080600060608486031215613445578283fd5b61344e8461308f565b925060208401359150604084013560ff8116811461346a578182fd5b809150509250925092565b600060208284031215613486578081fd5b81518015158114611de5578182fd5b6000602082840312156134a6578081fd5b81356001600160e01b031981168114611de5578182fd5b6000806000606084860312156134d1578081fd5b6134da84613130565b92506134e860208501613130565b9150604084015163ffffffff8116811461346a578182fd5b600060208284031215613511578081fd5b5035919050565b600060208284031215613529578081fd5b5051919050565b81835260006001600160fb1b03831115613548578081fd5b8260051b80836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b8381101561359357815187529582019590820190600101613577565b509495945050505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b6001600160a01b0389811682528816602082015260a0604082018190526000906135f5908301888a613530565b8281036060840152613608818789613530565b9050828103608084015261361d81858761359e565b9b9a5050505050505050505050565b6001600160a01b0387811682528616602082015260a06040820181905260009061365890830187613564565b828103606084015261366a8187613564565b9050828103608084015261367f81858761359e565b9998505050505050505050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a060808201819052600090612b52908301848661359e565b6000606082526136db606083018789613530565b82810360208401526136ee818688613530565b9150508260408301529695505050505050565b600060208252611de56020830184613564565b6000606082526137276060830186613564565b82810360208401526137398186613564565b915050826040830152949350505050565b60208082526026908201527f63616c63756c617465207265776172647320616e642054696d655061737365646040820152651032b93937b960d11b606082015260800190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600082198211156138395761383961388f565b500190565b60008160001904831182151516156138585761385861388f565b500290565b60008282101561386f5761386f61388f565b500390565b60006000198214156138885761388861388f565b5060010190565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220363a956a85ea14155ae7c2e23a92755e77ab08c0bd02c27aafa304683f45790864736f6c6343000803003300000000000000000000000061107a409fffe1965126aa456af679719695c69c000000000000000000000000fca68d9d45e0ebeb569b3e9ad2872c9e8d7a75ba

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102535760003560e01c8063715018a611610146578063a694fc3a116100c3578063e6a027d111610087578063e6a027d1146105f1578063f23a6e6114610604578063f2fde38b14610624578063f686f76d14610637578063faaec8491461064a578063fe47a8a71461065357610253565b8063a694fc3a1461053c578063aa381fc61461054f578063adce53e114610562578063bc197c8114610585578063c27bec20146105c057610253565b80638da5cb5b1161010a5780638da5cb5b146104d25780639616d0b8146104e35780639b427368146104f65780639dcc36da14610509578063a1fe277c1461051c57610253565b8063715018a61461045d5780637b74a4d514610465578063817b1cd2146104785780638456cb59146104815780638cf070581461048957610253565b8063440d7c7a116101d45780635dcac841116101985780635dcac841146103d35780635fcbd285146103e657806369163daa146103fe5780636a93edaf146104115780636f784d6b1461044a57610253565b8063440d7c7a14610391578063447d4ea9146103a45780634ca19fd6146103b75780634e71d92d146103c05780635c975abb146103c857610253565b806325280d541161021b57806325280d541461032e57806327e235e31461034e5780632def66201461036e57806339dc50f5146103765780633f4ba83a1461038957610253565b806301ffc9a714610258578063049f2d8a146102805780631d3c5b0e146102ae578063241b4a2d146102ee57806324ec5a7814610303575b600080fd5b61026b610266366004613495565b61065c565b60405190151581526020015b60405180910390f35b6102a061028e366004613147565b60076020526000908152604090205481565b604051908152602001610277565b6102dc6102bc3660046133a2565b600960209081526000928352604080842090915290825290205460ff1681565b60405160ff9091168152602001610277565b6103016102fc3660046133cb565b610695565b005b610316610311366004613500565b610701565b6040516001600160a01b039091168152602001610277565b6102a061033c366004613147565b60056020526000908152604090205481565b6102a061035c366004613147565b60046020526000908152604090205481565b61030161072b565b6102a0610384366004613147565b610785565b610301610801565b61026b61039f3660046133a2565b610835565b6103016103b23660046132fb565b610865565b6102a060115481565b610301610980565b60025460ff1661026b565b6103016103e1366004613500565b610c6c565b6002546103169061010090046001600160a01b031681565b61030161040c3660046132fb565b610e2a565b6102a061041f366004613161565b6001600160a01b039182166000908152600b6020908152604080832093909416825291909152205490565b6102a061045836600461324a565b610ed5565b610301610f60565b6102a0610473366004613147565b610f94565b6102a060065481565b610301611179565b61026b61049736600461324a565b6001600160a01b038084166000908152600b6020908152604080832093861683529281528282208483526001019052205460ff169392505050565b6000546001600160a01b0316610316565b6102a06104f1366004613147565b6111ab565b610301610504366004613500565b61122a565b6103016105173660046133cb565b611294565b61052f61052a366004613161565b61134e565b6040516102779190613701565b61030161054a366004613500565b6113c7565b6102a061055d366004613147565b611423565b61026b610570366004613147565b600e6020526000908152604090205460ff1681565b6105a7610593366004613193565b63bc197c8160e01b98975050505050505050565b6040516001600160e01b03199091168152602001610277565b6102a06105ce36600461324a565b600a60209081526000938452604080852082529284528284209052825290205481565b6103016105ff366004613431565b61145b565b6105a7610612366004613285565b63f23a6e6160e01b9695505050505050565b610301610632366004613147565b611621565b600354610316906001600160a01b031681565b6102a0600c5481565b6102a060085481565b60006001600160e01b03198216630271189760e51b148061068d57506301ffc9a760e01b6001600160e01b03198316145b90505b919050565b60025460ff16156106c15760405162461bcd60e51b81526004016106b890613790565b60405180910390fd5b600260015414156106e45760405162461bcd60e51b81526004016106b8906137ef565b60026001556106f685858585856116c2565b505060018055505050565b600d818154811061071157600080fd5b6000918252602090912001546001600160a01b0316905081565b60025460ff161561074e5760405162461bcd60e51b81526004016106b890613790565b600260015414156107715760405162461bcd60e51b81526004016106b8906137ef565b600260015561077f336118ba565b60018055565b6001600160a01b038116600090815260046020526040812054806107ad576000915050610690565b60008060006107bd866000611c14565b9250925092506000831180156107d1575060015b6107ed5760405162461bcd60e51b81526004016106b89061374a565b6107f78383611dd9565b9695505050505050565b6000546001600160a01b0316331461082b5760405162461bcd60e51b81526004016106b8906137ba565b610833611dec565b565b6001600160a01b038216600090815260096020908152604080832084845290915290205460ff1615155b92915050565b60025460ff16156108885760405162461bcd60e51b81526004016106b890613790565b600260015414156108ab5760405162461bcd60e51b81526004016106b8906137ef565b60026001558483146108ff5760405162461bcd60e51b815260206004820152601e60248201527f69647320616e642076616c756573206c656e677468206d69736d61746368000060448201526064016106b8565b61097333308989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b9182918501908490808284376000920191909152508a9250899150611e7f9050565b5050600180555050505050565b60025460ff16156109a35760405162461bcd60e51b81526004016106b890613790565b600260015414156109c65760405162461bcd60e51b81526004016106b8906137ef565b60026001553360009081526004602052604090205480610a285760405162461bcd60e51b815260206004820152601a60248201527f62616c616e63652073686f756c64206d6f7265207468616e203000000000000060448201526064016106b8565b6000806000610a38336000611c14565b925092509250600083118015610a4c575060015b610a685760405162461bcd60e51b81526004016106b89061374a565b6000610a748484611dd9565b905060008111610ac65760405162461bcd60e51b815260206004820152601f60248201527f636c61696d20696e746572657374206d757374206d6f7265207468616e20300060448201526064016106b8565b806008541015610b295760405162461bcd60e51b815260206004820152602860248201527f746f74616c2066756e64696e67206e6f7420656e6f75676820746f20706179206044820152671a5b9d195c995cdd60c21b60648201526084016106b8565b600854610b369082611dd9565b6008556000423360008181526005602052604090819020839055600354905163a9059cbb60e01b81526004810192909252602482018590529192506001600160a01b039091169063a9059cbb90604401602060405180830381600087803b158015610ba057600080fd5b505af1158015610bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd89190613475565b610c1d5760405162461bcd60e51b815260206004820152601660248201527518db185a5b4e881d1c985b9cd9995c8819985a5b195960521b60448201526064016106b8565b604080518781526020810184905290810182905233907f9cdcf2f7714cca3508c7f0110b04a90a80a3a8dd0e35de99689db74d28c5383e9060600160405180910390a250506001805550505050565b60026001541415610c8f5760405162461bcd60e51b81526004016106b8906137ef565b600260015580610ce15760405162461bcd60e51b815260206004820152601d60248201527f5f616d6f756e742073686f756c64206265206d6f7265207468616e203000000060448201526064016106b8565b3360009081526007602052604081208054839290610d00908490613826565b925050819055508060086000828254610d199190613826565b90915550506003546040516323b872dd60e01b8152336004820152306024820152604481018390526001600160a01b03909116906323b872dd90606401602060405180830381600087803b158015610d7057600080fd5b505af1158015610d84573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610da89190613475565b610dea5760405162461bcd60e51b81526020600482015260136024820152721d1c985b9cd9995c919c9bdb4819985a5b1959606a1b60448201526064016106b8565b60408051828152426020820152815133927f3b31cbadfd3fd939750f09d3bdbd6c0531dde23f05d55dcc202798f39d090895928290030190a25060018055565b60025460ff1615610e4d5760405162461bcd60e51b81526004016106b890613790565b60026001541415610e705760405162461bcd60e51b81526004016106b8906137ef565b6002600155848314610ec45760405162461bcd60e51b815260206004820152601e60248201527f69647320616e642076616c756573206c656e677468206d69736d61746368000060448201526064016106b8565b6109733033898989898989896120ef565b600082604051627eeac760e11b81526001600160a01b03868116600483015260248201859052919091169062fdd58e9060440160206040518083038186803b158015610f2057600080fd5b505afa158015610f34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f589190613518565b949350505050565b6000546001600160a01b03163314610f8a5760405162461bcd60e51b81526004016106b8906137ba565b6108336000612429565b6001600160a01b03811660009081526004602052604081205480610fbc576000915050610690565b60115460005b600d5481101561117157600061100d86600d8481548110610ff357634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031661134e565b9050600081511161101e575061115f565b60005b815181101561115c57600082828151811061104c57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000600a60008a6001600160a01b03166001600160a01b031681526020019081526020016000206000600d87815481106110a057634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b031683528281019390935260409182018120858252909252812054600d8054919350600991839190899081106110fb57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168352828101939093526040918201812086825290925290205460ff16905061114461113d8383612479565b8890612485565b9650505050808061115490613874565b915050611021565b50505b8061116981613874565b915050610fc2565b509392505050565b6000546001600160a01b031633146111a35760405162461bcd60e51b81526004016106b8906137ba565b610833612491565b6003546040516370a0823160e01b81526001600160a01b03838116600483015260009216906370a08231906024015b60206040518083038186803b1580156111f257600080fd5b505afa158015611206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061068d9190613518565b6000546001600160a01b031633146112545760405162461bcd60e51b81526004016106b8906137ba565b6011819055604080518281523360208201527f6766a9d3fdc5e039898b997749d240694539e82595bf4f16d66006f97431b126910160405180910390a150565b60025460ff16156112b75760405162461bcd60e51b81526004016106b890613790565b600260015414156112da5760405162461bcd60e51b81526004016106b8906137ef565b60026001556112e98585610835565b61133f5760405162461bcd60e51b815260206004820152602160248201527f7374616b654e66743a206e6674206964206e6f7420696e2077686974656c69736044820152601d60fa1b60648201526084016106b8565b6106f6333087878787876124e9565b6001600160a01b038083166000908152600b602090815260408083209385168352928152908290208054835181840281018401909452808452606093928301828280156113ba57602002820191906000526020600020905b8154815260200190600101908083116113a6575b5050505050905092915050565b60025460ff16156113ea5760405162461bcd60e51b81526004016106b890613790565b6002600154141561140d5760405162461bcd60e51b81526004016106b8906137ef565b600260015561141c3382612675565b5060018055565b6002546040516370a0823160e01b81526001600160a01b038381166004830152600092610100900416906370a08231906024016111da565b6000546001600160a01b031633146114855760405162461bcd60e51b81526004016106b8906137ba565b6001600160a01b0383166114d35760405162461bcd60e51b81526020600482015260156024820152741b999d081859191c995cdcc81a5b98dbdc9c9958dd605a1b60448201526064016106b8565b6000821180156114e6575060008160ff16115b6115295760405162461bcd60e51b815260206004820152601460248201527306e667420616e6420617079206d757374203e20360641b60448201526064016106b8565b6001600160a01b0383166000908152600e602052604090205460ff166115ad57600d805460018082019092557fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50180546001600160a01b0319166001600160a01b0386169081179091556000908152600e60205260409020805460ff191690911790555b6001600160a01b0383166000818152600960209081526040808320868452825291829020805460ff861660ff199091168117909155825186815291820152338183015290517f5e244736b7eeb9972c03e5b93e7d50f2509b03864d8aa9f1339adeef0a7d24639181900360600190a2505050565b6000546001600160a01b0316331461164b5760405162461bcd60e51b81526004016106b8906137ba565b6001600160a01b0381166116b05760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016106b8565b6116b981612429565b50565b3b151590565b60006116cd33610785565b336000908152600460205260409020549091506116eb5760006116ed565b425b33600090815260056020908152604080832093909355600a81528282206001600160a01b038a168352815282822088835290522054848110156117725760405162461bcd60e51b815260206004820181905260248201527f696e73756666696369656e742062616c616e636520666f7220756e7374616b6560448201526064016106b8565b61177c8186611dd9565b336000908152600a602090815260408083206001600160a01b038c16845282528083208a8452909152902055600c546117b59086611dd9565b600c55336000908152600a602090815260408083206001600160a01b038b16845282528083208984529091529020546117f2576117f28787612863565b604051637921219560e11b81526001600160a01b0388169063f242432a9061182890309033908b908b908b908b9060040161368c565b600060405180830381600087803b15801561184257600080fd5b505af1158015611856573d6000803e3d6000fd5b5050505061186433836129f7565b6001600160a01b038716337f5a62b64705b9e7c31cb4c877f4cf7d9b38a6c01cd0e00e76c8f43a03becc02348888426040805193845260208401929092529082015260600160405180910390a350505050505050565b336000908152600460205260409020548061190c5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742066756e647360701b60448201526064016106b8565b600080600061191c856000611c14565b9250925092506000831180156119325750600081115b61198c5760405162461bcd60e51b815260206004820152602560248201527f746f74616c57697468496e7465726573743c3d30206f722074696d6550617373604482015264065643c3d360dc1b60648201526084016106b8565b6001600160a01b038516600090815260046020908152604080832083905560059091528120556006546119bf9085611dd9565b60065560006119ce8484611dd9565b9050600080821180156119e357508160085410155b156119fc575060085481906119f89082611dd9565b6008555b8015611ad45760035460405163a9059cbb60e01b81526001600160a01b038981166004830152602482018490529091169063a9059cbb90604401602060405180830381600087803b158015611a5057600080fd5b505af1158015611a64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a889190613475565b611ad45760405162461bcd60e51b815260206004820152601c60248201527f5f756e7374616b6520756d69207472616e73666572206661696c65640000000060448201526064016106b8565b60025460405163a9059cbb60e01b81526001600160a01b038981166004830152602482018990526101009092049091169063a9059cbb90604401602060405180830381600087803b158015611b2857600080fd5b505af1158015611b3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b609190613475565b611bac5760405162461bcd60e51b815260206004820152601c60248201527f5f756e7374616b653a206c70207472616e73666572206661696c65640000000060448201526064016106b8565b866001600160a01b03167f055f388d8102e9e2bfeaa944b25b4cdb0c06fd1c42d5c2812a8f3c7ac1aa26d3611be089610f94565b60408051918252602082018a905281810185905260608201879052426080830152519081900360a00190a250505050505050565b6001600160a01b03821660009081526004602052604081205481908190818515611c3e5785611c40565b815b6001600160a01b038816600090815260056020526040812054919250611c664283611dd9565b90506001811015611c8357600096508695509350611dd292505050565b6000611c8e8a610f94565b90506000600260019054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611ce057600080fd5b505afa158015611cf4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d189190613518565b90506000600260019054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015611d6a57600080fd5b505afa158015611d7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611da291906134bd565b505090506000611db3878484612aea565b90506000611dc2828787612b0e565b9b50909950939750505050505050505b9250925092565b6000611de5828461385d565b9392505050565b60025460ff16611e355760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016106b8565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6000611e8a88610785565b6001600160a01b038916600090815260046020526040902054909150611eb1576000611eb3565b425b6001600160a01b0389166000908152600560205260408120919091555b855181101561201d576000868281518110611efb57634e487b7160e01b600052603260045260246000fd5b602002602001015190506000868381518110611f2757634e487b7160e01b600052603260045260246000fd5b60200260200101519050611f3b8983610835565b611f875760405162461bcd60e51b815260206004820152601760248201527f6e6674206964206e6f7420696e2077686974656c69737400000000000000000060448201526064016106b8565b6001600160a01b03808c166000908152600a60209081526040808320938d16835292815282822085835290522054611fbf9082612485565b6001600160a01b03808d166000908152600a60209081526040808320938e16835292815282822086835290522055611ff88b8a84612b5e565b600c546120059082612485565b600c555081905061201581613874565b915050611ed0565b50604051631759616b60e11b81526001600160a01b03871690632eb2c2d690612054908b908b908a908a908a908a9060040161362c565b600060405180830381600087803b15801561206e57600080fd5b505af1158015612082573d6000803e3d6000fd5b5050505061209033826129f7565b856001600160a01b0316886001600160a01b03167fc2f970af6b072882b84bbf83c8fc68080b10e5847ab197c629e18c0ad406d39287876120ce4290565b6040516120dd93929190613714565b60405180910390a35050505050505050565b60006120fa8a610785565b6001600160a01b038b16600090815260046020526040902054909150612121576000612123565b425b6001600160a01b038b166000908152600560205260408120919091555b8681101561235c57600088888381811061216a57634e487b7160e01b600052603260045260246000fd5b905060200201359050600087878481811061219557634e487b7160e01b600052603260045260246000fd5b9050602002013590506000600a6000336001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b031681526020019081526020016000206000848152602001908152602001600020549050818110156122585760405162461bcd60e51b8152602060048201526024808201527f696e73756666696369656e74206e66742062616c616e636520666f7220756e7360448201526374616b6560e01b60648201526084016106b8565b6122628183611dd9565b600a6000336001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b031681526020019081526020016000206000858152602001908152602001600020819055506122d482600c54611dd990919063ffffffff16565b600c81905550600a6000336001600160a01b03166001600160a01b0316815260200190815260200160002060008d6001600160a01b03166001600160a01b0316815260200190815260200160002060008481526020019081526020016000205460001415612346576123468c84612863565b505050808061235490613874565b915050612140565b50604051631759616b60e11b81526001600160a01b03891690632eb2c2d690612397908d908d908c908c908c908c908c908c906004016135c8565b600060405180830381600087803b1580156123b157600080fd5b505af11580156123c5573d6000803e3d6000fd5b505050506123d333826129f7565b6001600160a01b038816337f77455a41e4b718cead56169d2fdc4d2de52ca373c87aca655f14d5131e19941089898989426040516124159594939291906136c7565b60405180910390a350505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000611de5828461383e565b6000611de58284613826565b60025460ff16156124b45760405162461bcd60e51b81526004016106b890613790565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611e623390565b60006124f488610785565b6001600160a01b03891660009081526004602052604090205490915061251b57600061251d565b425b6001600160a01b03808a16600090815260056020908152604080832094909455600a8152838220928a16825291825282812088825290915220546125619085612485565b6001600160a01b03808a166000908152600a60209081526040808320938b1683529281528282208983529052205561259a888787612b5e565b600c546125a79085612485565b600c55604051637921219560e11b81526001600160a01b0387169063f242432a906125e0908b908b908a908a908a908a9060040161368c565b600060405180830381600087803b1580156125fa57600080fd5b505af115801561260e573d6000803e3d6000fd5b5050505061261c88826129f7565b856001600160a01b0316886001600160a01b03167f04d24c87a9fd202d8e2c705a0d245fdd66387174bf8105618f4ecb0100ddf0e1878761265a4290565b604080519384526020840192909252908201526060016120dd565b600081116126d05760405162461bcd60e51b815260206004820152602260248201527f7374616b6520616d6f756e742073686f756c64206265206d6f7265207468616e604482015261020360f41b60648201526084016106b8565b60006126db83610785565b6001600160a01b0384166000908152600460205260409020549091506127019083612485565b6001600160a01b0384166000908152600460205260409020556006546127279083612485565b6006556001600160a01b0383166000818152600560209081526040918290204290819055825186815291820181905282519093927f1449c6dd7851abc30abf37f57715f492010519147cc2652fbc38202c18a6ee90928290030190a26002546040516323b872dd60e01b81526001600160a01b03868116600483015230602483015260448201869052610100909204909116906323b872dd90606401602060405180830381600087803b1580156127dd57600080fd5b505af11580156127f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128159190613475565b6128535760405162461bcd60e51b815260206004820152600f60248201526e1d1c985b9cd9995c8819985a5b1959608a1b60448201526064016106b8565b61285d84836129f7565b50505050565b336000908152600b602090815260408083206001600160a01b038616845290915290208054819060018201906128ec5760405162461bcd60e51b815260206004820152602860248201527f72656d6f76652075736572206e6674206964732c20696473206c656e6774682060448201526706d757374203e20360c41b60648201526084016106b8565b60005b82548110156129ef578483828154811061291957634e487b7160e01b600052603260045260246000fd5b906000526020600020015414156129dd578254839061293a9060019061385d565b8154811061295857634e487b7160e01b600052603260045260246000fd5b906000526020600020015483828154811061298357634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101929092558681529083905260409020805460ff1916905582548390806129c657634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590555b806129e781613874565b9150506128ef565b505050505050565b60008111612a0457612ae6565b600854612a119082611dd9565b60085560035460405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490529091169063a9059cbb90604401602060405180830381600087803b158015612a6257600080fd5b505af1158015612a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a9a9190613475565b612ae65760405162461bcd60e51b815260206004820152601c60248201527f7472616e7366657220756d6920696e746572657374206661696c65640000000060448201526064016106b8565b5050565b600080612af78585612bd1565b905060006107f782856001600160701b0316612c08565b600080612b1f8363bbf81e00612bd1565b90506000612b36612b306001612c70565b83612ca3565b90506000612b448287612cd7565b90506000612b528289612c08565b98975050505050505050565b6001600160a01b038084166000908152600b6020908152604080832093861683529281528282208483526001810191829052929091205482919060ff166129ef57815460018082018455600093845260208085209092018690559483525260409020805460ff1916909217909155505050565b600081612bdd57600080fd5b6000612be98484612ef5565b905060016001607f1b036001600160801b0382161115611de557600080fd5b600081612c175750600061085f565b600083600f0b1215612c2857600080fd5b600f83900b6001600160801b038316810260401c90608084901c026001600160c01b03811115612c5757600080fd5b60401b8119811115612c6857600080fd5b019392505050565b6000677fffffffffffffff198212158015612c935750677fffffffffffffff8213155b612c9c57600080fd5b5060401b90565b6000600f83810b9083900b0160016001607f1b03198112801590612cce575060016001607f1b038113155b611de557600080fd5b600080600084600f0b128015612cf05750826001166001145b905060008085600f0b12612d045784612d09565b846000035b6001600160801b03169050600160801b680100000000000000008211612da357603f82901b91505b8415612d9b576001851615612d46578102607f1c5b908002607f1c906002851615612d5c578102607f1c5b908002607f1c906004851615612d72578102607f1c5b908002607f1c906008851615612d88578102607f1c5b60049490941c93908002607f1c90612d31565b60401c612eb9565b603f600160601b831015612dbd5760209290921b91601f19015b600160701b831015612dd55760109290921b91600f19015b600160781b831015612ded5760089290921b91600719015b6001607c1b831015612e055760049290921b91600319015b6001607e1b831015612e1d5760029290921b91600119015b6001607f1b831015612e355760019290921b91600019015b60005b8615612ea25760408210612e4b57600080fd5b6001871615612e7157918302607f1c918101600160801b831115612e7157600192831c92015b928002607f1c9260019190911b90600160801b8410612e9657600193841c9391909101905b600187901c9650612e38565b60408110612eaf57600080fd5b6040039190911c90505b600083612ec65781612ecb565b816000035b905060016001607f1b03198112801590612eec575060016001607f1b038113155b6107f757600080fd5b600081612f0157600080fd5b60006001600160c01b038411612f3a5782604085901b81612f3257634e487b7160e01b600052601260045260246000fd5b04905061307b565b60c084811c6401000000008110612f53576020918201911c5b620100008110612f65576010918201911c5b6101008110612f76576008918201911c5b60108110612f86576004918201911c5b60048110612f96576002918201911c5b60028110612fa5576001820191505b60bf820360018603901c6001018260ff0387901b81612fd457634e487b7160e01b600052601260045260246000fd5b0492506001600160801b03831115612feb57600080fd5b608085901c83026001600160801b038616840260c088901c604089901b82811015613017576001820391505b608084901b9290038281101561302e576001820391505b829003608084901c821461305257634e487b7160e01b600052600160045260246000fd5b88818161306f57634e487b7160e01b600052601260045260246000fd5b04870196505050505050505b6001600160801b03811115611de557600080fd5b80356001600160a01b038116811461069057600080fd5b60008083601f8401126130b7578182fd5b50813567ffffffffffffffff8111156130ce578182fd5b6020830191508360208260051b85010111156130e957600080fd5b9250929050565b60008083601f840112613101578182fd5b50813567ffffffffffffffff811115613118578182fd5b6020830191508360208285010111156130e957600080fd5b80516001600160701b038116811461069057600080fd5b600060208284031215613158578081fd5b611de58261308f565b60008060408385031215613173578081fd5b61317c8361308f565b915061318a6020840161308f565b90509250929050565b60008060008060008060008060a0898b0312156131ae578384fd5b6131b78961308f565b97506131c560208a0161308f565b9650604089013567ffffffffffffffff808211156131e1578586fd5b6131ed8c838d016130a6565b909850965060608b0135915080821115613205578586fd5b6132118c838d016130a6565b909650945060808b0135915080821115613229578384fd5b506132368b828c016130f0565b999c989b5096995094979396929594505050565b60008060006060848603121561325e578283fd5b6132678461308f565b92506132756020850161308f565b9150604084013590509250925092565b60008060008060008060a0878903121561329d578182fd5b6132a68761308f565b95506132b46020880161308f565b94506040870135935060608701359250608087013567ffffffffffffffff8111156132dd578283fd5b6132e989828a016130f0565b979a9699509497509295939492505050565b60008060008060008060006080888a031215613315578283fd5b61331e8861308f565b9650602088013567ffffffffffffffff8082111561333a578485fd5b6133468b838c016130a6565b909850965060408a013591508082111561335e578485fd5b61336a8b838c016130a6565b909650945060608a0135915080821115613382578384fd5b5061338f8a828b016130f0565b989b979a50959850939692959293505050565b600080604083850312156133b4578182fd5b6133bd8361308f565b946020939093013593505050565b6000806000806000608086880312156133e2578081fd5b6133eb8661308f565b94506020860135935060408601359250606086013567ffffffffffffffff811115613414578182fd5b613420888289016130f0565b969995985093965092949392505050565b600080600060608486031215613445578283fd5b61344e8461308f565b925060208401359150604084013560ff8116811461346a578182fd5b809150509250925092565b600060208284031215613486578081fd5b81518015158114611de5578182fd5b6000602082840312156134a6578081fd5b81356001600160e01b031981168114611de5578182fd5b6000806000606084860312156134d1578081fd5b6134da84613130565b92506134e860208501613130565b9150604084015163ffffffff8116811461346a578182fd5b600060208284031215613511578081fd5b5035919050565b600060208284031215613529578081fd5b5051919050565b81835260006001600160fb1b03831115613548578081fd5b8260051b80836020870137939093016020019283525090919050565b6000815180845260208085019450808401835b8381101561359357815187529582019590820190600101613577565b509495945050505050565b60008284528282602086013780602084860101526020601f19601f85011685010190509392505050565b6001600160a01b0389811682528816602082015260a0604082018190526000906135f5908301888a613530565b8281036060840152613608818789613530565b9050828103608084015261361d81858761359e565b9b9a5050505050505050505050565b6001600160a01b0387811682528616602082015260a06040820181905260009061365890830187613564565b828103606084015261366a8187613564565b9050828103608084015261367f81858761359e565b9998505050505050505050565b6001600160a01b03878116825286166020820152604081018590526060810184905260a060808201819052600090612b52908301848661359e565b6000606082526136db606083018789613530565b82810360208401526136ee818688613530565b9150508260408301529695505050505050565b600060208252611de56020830184613564565b6000606082526137276060830186613564565b82810360208401526137398186613564565b915050826040830152949350505050565b60208082526026908201527f63616c63756c617465207265776172647320616e642054696d655061737365646040820152651032b93937b960d11b606082015260800190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600082198211156138395761383961388f565b500190565b60008160001904831182151516156138585761385861388f565b500290565b60008282101561386f5761386f61388f565b500390565b60006000198214156138885761388861388f565b5060010190565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220363a956a85ea14155ae7c2e23a92755e77ab08c0bd02c27aafa304683f45790864736f6c63430008030033

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

00000000000000000000000061107a409fffe1965126aa456af679719695c69c000000000000000000000000fca68d9d45e0ebeb569b3e9ad2872c9e8d7a75ba

-----Decoded View---------------
Arg [0] : _umiAddress (address): 0x61107a409fFFe1965126aa456Af679719695C69C
Arg [1] : _lpAddress (address): 0xFCa68D9D45E0ebEB569b3E9ad2872C9e8D7a75BA

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000061107a409fffe1965126aa456af679719695c69c
Arg [1] : 000000000000000000000000fca68d9d45e0ebeb569b3e9ad2872c9e8d7a75ba


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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