ETH Price: $3,322.74 (+2.80%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Guardians

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 11 : Guardians.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "./libraries/GuardianTimeMath.sol";
import "./interfaces/IERC11554K.sol";
import "./interfaces/IFeesManager.sol";
import "./interfaces/IERC11554KController.sol";

/**
 * @dev Guardians management contract version 0.2.2
 * Sets guardians parameters, fees, info
 * by guardians themselves and the protocol.
 */
contract Guardians is Initializable, OwnableUpgradeable {
    /// @dev Guardian Info struct.
    struct GuardianInfo {
        /// @notice Hashed physical address of a guardian.
        bytes32 addressHash; //0
        /// @notice Logo of a guardian.
        string logo; //1
        /// @notice Name of a guardian.
        string name; //2
        /// @notice A guardian's redirect URI for future authentication flows.
        string redirect; //3
        /// @notice Guardian's policy.
        string policy; //4
        /// @notice Active status for a guardian
        bool isActive; //5
        /// @notice Private status for a guardian.
        bool isPrivate; //6
    }

    enum GuardianFeeRatePeriods {
        SECONDS,
        MINUTES,
        HOURS,
        DAYS
    }

    /// @dev Guardian class struct.
    struct GuardianClass {
        /// @notice Maximum insurance on-chain coverage.
        uint256 maximumCoverage; //0
        /// @notice Minting fee. Stored scaled by 10^18.
        uint256 mintingFee; //1
        /// @notice Redemption fee. Stored scaled by 10^18.
        uint256 redemptionFee; //2
        /// @notice The base unit for the guardian fee rate.
        uint256 guardianFeeRatePeriod; //3
        /// @notice Guardian fee rate per period. Stored scaled by 10^18.
        uint256 guardianFeeRate; //4
        /// @notice Guardian fee rate historic minimum.
        uint256 guardianFeeRateMinimum; //5
        /// @notice Last Guardian fee rate increase update timestamp.
        uint256 lastGuardianFeeRateIncrease; //6
        /// @notice Is guardian class active.
        bool isActive; //7
        /// @notice Guardian URI for metadata.
        string uri; //8
    }

    uint256 public constant SECOND = 1;
    uint256 public constant MINUTE = 60;
    uint256 public constant HOUR = MINUTE * 60;
    uint256 public constant DAY = HOUR * 24;

    /// @notice Fee manager contract.
    IFeesManager public feesManager;

    /// @notice Controller contract.
    IERC11554KController public controller;

    /// @notice Percentage factor with 0.01% precision. For internal float calculations.
    uint256 public constant PERCENTAGE_FACTOR = 10000;

    /// @notice Minimum minting request fee.
    uint256 public minimumRequestFee;
    /// @notice Minimum time window for guardian fee rate increase.
    uint256 public guardianFeeSetWindow;
    /// @notice Maximum guardian fee rate percentage increase during single fee set, 0.01% precision.
    uint256 public maximumGuardianFeeSet;
    /// @notice Minimum storage time an item needs to have for transfers.
    uint256 public minStorageTime;

    /// @notice Is an address a 4K whitelisted guardian.
    mapping(address => bool) public isWhitelisted;

    /// @notice Metadata info about a guardian
    mapping(address => GuardianInfo) public guardianInfo;

    /// @notice Guardians whitelisted users for services.
    mapping(address => mapping(address => bool)) public guardianWhitelist;
    /// @notice To whom (if) guardian delegated functions to execute
    mapping(address => address) public delegated;
    /// @notice  Guardian classes of a particular guardian.
    mapping(address => GuardianClass[]) public guardiansClasses;
    /// @notice How much items with id guardian keeps.
    /// guardian -> collection -> id -> amount
    mapping(address => mapping(IERC11554K => mapping(uint256 => uint256)))
        public stored;
    /// @notice At which guardian is each item stored.
    /// collection address -> item id -> guardian address
    mapping(IERC11554K => mapping(uint256 => address)) public whereItemStored;

    /// @notice In which guardian class is the item? (within the context of the guardian where the item is stored)
    /// collection address -> item id -> guardian class index
    mapping(IERC11554K => mapping(uint256 => uint256)) public itemGuardianClass;

    /// @notice Mapping from a token holder address to a collection to an item id, to the date until storage has been paid.
    mapping(address => mapping(IERC11554K => mapping(uint256 => uint256)))
        public guardianFeePaidUntil;

    /// @notice Mapping from a collection, to item id, to the date until storage has been paid (globally, collectively for all users).
    /// @dev DEPRECATED
    mapping(IERC11554K => mapping(uint256 => uint256))
        public globalItemGuardianFeePaidUntil;

    /// @notice user -> collection -> item id -> num items in repossession
    /// @notice Number of items in a collection that a user has in repossession.
    mapping(address => mapping(IERC11554K => mapping(uint256 => uint256)))
        public inRepossession;

    /// @notice guardian => delegatee => true if guardian delegates some functions to delegatee.
    mapping(address => mapping(address => bool)) public delegatedAll;

    /// @notice guardian => collection => delegatee if guardian delegates some functions to delegatee.
    mapping(address => mapping(IERC11554K => address))
        public delegatedCollection;

    /// @notice Version of the contract
    bytes32 public version;

    /// @dev Guardian has been added.
    event GuardianAdded(address indexed guardian, GuardianInfo newGuardianInfo);
    /// @dev Guardian has been removed.
    event GuardianRemoved(address indexed guardian);
    /// @dev Guardian has been modified
    event GuardianModified(
        address indexed guardian,
        uint8 fieldIndexModified,
        GuardianInfo newGuardianInfo
    );
    /// @dev Guardian class has been added.
    event GuardianClassAdded(
        address indexed guardian,
        uint256 classID,
        GuardianClass newGuardianClass
    );
    /// @dev Guardian class has been modified.
    event GuardianClassModified(
        address indexed guardian,
        uint256 classID,
        uint8 fieldIndexModified,
        GuardianClass newGuardianClass
    );

    /// @dev Item has been stored by the guardian
    event ItemStored(
        address indexed guardian,
        uint256 classID,
        uint256 tokenId,
        IERC11554K collection
    );

    /// @dev Item has been moved from one guardian to another
    event ItemMoved(
        address indexed fromGuardian,
        address indexed toGuardian,
        uint256 toGuardianClassId,
        uint256 tokenId,
        IERC11554K collection
    );

    /// @dev Storage time has been purchased for an item.
    event StorageTimeAdded(
        uint256 indexed id,
        address indexed guardian,
        uint256 timeAmount,
        address beneficiary,
        IERC11554K collection
    );
    /// @dev Item(s) have been set for repossession.
    event SetForRepossession(
        uint256 indexed id,
        IERC11554K indexed collection,
        address indexed guardian,
        uint256 amount
    );
    /// @dev Guardian has been added - with metadata.
    event GuardianRegistered(
        address indexed guardian,
        GuardianInfo newGuardianInfo
    );

    /// @dev Errors
    error GuardianNotWhitelisted();
    error CallerNotController();
    error NotCallersGuardianData();
    error MinStorageTimeTooLow();
    error TooManyReposessionItems();
    error OldGuardianAvailable();
    error NewGuardianUnavailable();
    error ClassNotActive();
    error NotGuardianOfItems();
    error FreeStorageItemsCantBeRepossessed();
    error GuardianFeePaidUntilStillInFuture();
    error NoItemsToRepossess();
    error MintingFeeTooLow();
    error DifferentPeriodRequired();
    error CollectionIsNotActiveOrLinked();
    error GuardianClassFeeRateTooLow();
    error GuardianFeeTooLow();
    error BeneficiaryDoesNotOwnItem();
    error GuardianDoesNotStoreItem();
    error ItemNotYetMinted();
    error GuardianFeeNotChangeableOnFreeStorageClass();
    error GuardianFeeWindowHasntPassed();
    error GuardianFeeRateLimitExceeded();

    /**
     * @dev Only whitelisted guardian modifier.
     */
    modifier onlyWhitelisted(address guardian) {
        if (!isWhitelisted[guardian]) {
            revert GuardianNotWhitelisted();
        }
        _;
    }

    /**
     * @dev Only controller modifier.
     */
    modifier onlyController() {
        if (_msgSender() != address(controller)) {
            revert CallerNotController();
        }
        _;
    }

    /**
     * @dev Only controller modifier.
     */
    modifier ifNotOwnerGuardianIsCaller(address guardian) {
        if (_msgSender() != owner()) {
            if (_msgSender() != guardian) {
                revert NotCallersGuardianData();
            }
        }
        _;
    }

    /**
     * @notice Initialize Guardians contract.
     * @param minimumRequestFee_ The minimum mint request fee.
     * @param guardianFeeSetWindow_ The window of time in seconds within a guardian is allowed to increase a guardian fee rate.
     * @param maximumGuardianFeeSet_ The max percentage increase that a guardian can increase a guardian fee rate by. Numerator that generates percentage, over the PERCENTAGE_FACTOR.
     * @param feesManager_ Fees manager contract address.
     * @param controller_ Controller contract address.
     * @param version_ Version of contract
     */
    function initialize(
        uint256 minimumRequestFee_,
        uint256 guardianFeeSetWindow_,
        uint256 maximumGuardianFeeSet_,
        IFeesManager feesManager_,
        IERC11554KController controller_,
        bytes32 version_
    ) external initializer {
        __Ownable_init();
        minimumRequestFee = minimumRequestFee_;
        guardianFeeSetWindow = guardianFeeSetWindow_;
        maximumGuardianFeeSet = maximumGuardianFeeSet_;
        minStorageTime = 7776000; // default 90 days
        feesManager = feesManager_;
        controller = controller_;
        version = version_;
    }

    /**
     * @notice Set controller.
     *
     * Requirements:
     *
     * 1) The caller must be a contract admin.
     * @param controller_ New address of controller contract.
     */
    function setController(
        IERC11554KController controller_
    ) external virtual onlyOwner {
        controller = controller_;
    }

    /**
     * @notice Set fees manager.
     *
     * Requirements:
     *
     * 1) The caller must be a contract admin.
     @param feesManager_ New address of fees manager contract.
     */
    function setFeesManager(
        IFeesManager feesManager_
    ) external virtual onlyOwner {
        feesManager = feesManager_;
    }

    /**
     * @notice Sets new min storage time.
     *
     * Requirements:
     *
     * 1) The caller must be a contract admin.
     * @param minStorageTime_ New minimum storage time that items require to have, in seconds.
     */
    function setMinStorageTime(
        uint256 minStorageTime_
    ) external virtual onlyOwner {
        if (minStorageTime_ == 0) {
            revert MinStorageTimeTooLow();
        }
        minStorageTime = minStorageTime_;
    }

    /**
     * @notice Sets minimum mining fee.
     *
     * Requirements:
     *
     * 1) The caller must be a contract owner.
     * @param minimumRequestFee_ New minumum mint request fee.
     */
    function setMinimumRequestFee(
        uint256 minimumRequestFee_
    ) external onlyOwner {
        minimumRequestFee = minimumRequestFee_;
    }

    /**
     * @notice Sets maximum Guardian fee rate set percentage.
     *
     * Requirements:
     *
     * 1) The caller must be a contract owner.
     * @param maximumGuardianFeeSet_ New max percentage increase that a guardian can increase a guardian fee rate by. Numerator that generates percentage, over the PERCENTAGE_FACTOR
     */
    function setMaximumGuardianFeeSet(
        uint256 maximumGuardianFeeSet_
    ) external onlyOwner {
        maximumGuardianFeeSet = maximumGuardianFeeSet_;
    }

    /**
     * @notice Sets minimum Guardian fee.
     *
     * Requirements:
     *
     * 1) The caller must be a contract owner.
     * @param guardianFeeSetWindow_ New window of time in seconds within a guardian is allowed to increase a guardian fee rate
     */
    function setGuardianFeeSetWindow(
        uint256 guardianFeeSetWindow_
    ) external onlyOwner {
        guardianFeeSetWindow = guardianFeeSetWindow_;
    }

    /**
     * @notice Does a batch adding of storage for all the items passed.
     * @param collections Array of collections that contain the items for which guardian time will be purchased.
     * @param beneficiaries Array of addresses that will be receiving the purchased guardian time.
     * @param ids Array of item ids for which guardian time will be purchased.
     * @param guardianFeeAmounts Array of guardian fee inputs for purchasing guardian time.
     */
    function batchAddStorageTime(
        IERC11554K[] calldata collections,
        address[] calldata beneficiaries,
        uint256[] calldata ids,
        uint256[] calldata guardianFeeAmounts
    ) external virtual {
        for (uint256 i = 0; i < ids.length; i++) {
            addStorageTime(
                collections[i],
                beneficiaries[i],
                ids[i],
                guardianFeeAmounts[i]
            );
        }
    }

    /**
     * @dev Externally called store item function by controller.
     * @param collection Address of the collection that the item being stored belongs to.
     * @param mintAddress Address of entity receiving the token(s).
     * @param id Item id of the item being stored.
     * @param guardian Address of guardian the item will be stored in.
     * @param guardianClassIndex Index of the guardian class the item will be stored in.
     * @param guardianFeeAmount Amount of fee that is being paid to purchase guardian time.
     * @param numItems Number of items being stored
     * @param feePayer The address of the entity paying the guardian fee.
     */
    function controllerStoreItem(
        IERC11554K collection,
        address mintAddress,
        uint256 id,
        address guardian,
        uint256 guardianClassIndex,
        uint256 guardianFeeAmount,
        uint256 numItems,
        address feePayer,
        IERC20Upgradeable paymentAsset
    ) external virtual onlyController {
        stored[guardian][collection][id] += numItems;
        whereItemStored[collection][id] = guardian;
        itemGuardianClass[collection][id] = guardianClassIndex;

        // Only needs to be done in non-free guardian classes
        if (
            guardiansClasses[guardian][guardianClassIndex].guardianFeeRate > 0
        ) {
            // Initialize paid until timelines on first ever mints
            if (guardianFeePaidUntil[mintAddress][collection][id] == 0) {
                guardianFeePaidUntil[mintAddress][collection][id] = block
                    .timestamp;
            }
            {
                uint256 addedStorageTime = GuardianTimeMath
                    .calculateAddedGuardianTime(
                        guardianFeeAmount,
                        guardiansClasses[guardian][guardianClassIndex]
                            .guardianFeeRate,
                        guardiansClasses[guardian][guardianClassIndex]
                            .guardianFeeRatePeriod,
                        numItems
                    );

                guardianFeePaidUntil[mintAddress][collection][
                    id
                ] += addedStorageTime;

                emit StorageTimeAdded(
                    id,
                    guardian,
                    addedStorageTime,
                    mintAddress,
                    collection
                );
            }

            feesManager.payGuardianFee(
                guardianFeeAmount,
                (guardiansClasses[guardian][guardianClassIndex]
                    .guardianFeeRate * numItems) /
                    getGuardianFeeRatePeriod(guardian, guardianClassIndex),
                guardian,
                guardianFeePaidUntil[mintAddress][collection][id],
                feePayer,
                paymentAsset
            );

            emit ItemStored(guardian, guardianClassIndex, id, collection);
        }
    }

    /**
     * @dev Externally called take item out function by controller.
     * @param guardian Address of guardian the item is being stored in.
     * @param collection Address of the collection that the item being stored belongs to.
     * @param id Item id of the item being stored.
     * @param numItems Number of items that are being taken out of the guardian.
     * @param from Address of the entity requesting the redemption/removal of the item(s).
     */
    function controllerTakeItemOut(
        address guardian,
        IERC11554K collection,
        uint256 id,
        uint256 numItems,
        address from
    ) external virtual onlyController {
        if (inRepossession[from][collection][id] >= numItems) {
            revert TooManyReposessionItems();
        }
        uint256 guardianClassFeeRate = getGuardianFeeRate(
            guardian,
            itemGuardianClass[collection][id]
        );

        uint256 guardianFeeRatePeriod = getGuardianFeeRatePeriod(
            guardian,
            itemGuardianClass[collection][id]
        );

        // No refunds
        // uint256 previousPaidUntil = guardianFeePaidUntil[from][collection][id];
        // uint256 guardianFeeRefundAmount;

        if (guardianClassFeeRate > 0) {
            // No refunds
            // guardianFeeRefundAmount =
            _shiftGuardianFeesOnTokenRedeem(
                from,
                collection,
                id,
                numItems,
                guardianClassFeeRate,
                guardianFeeRatePeriod
            );
        }

        stored[guardian][collection][id] -= numItems;
        if (stored[guardian][collection][id] == 0) {
            whereItemStored[collection][id] = address(0);
        }

        // No refunds
        /*
        uint256 guardianClassFeeRateMin = getGuardianFeeRateMinimum(guardian, itemGuardianClass[collection][id]);
        if (guardianClassFeeRate > 0) {
            feesManager.refundGuardianFee(
                guardianFeeRefundAmount,
                (guardianClassFeeRateMin * numItems) / guardianFeeRatePeriod,
                guardian,
                previousPaidUntil,
                from,
                paymentAsset
            );
        }
        */
    }

    /**
     * @notice Moves items from inactive guardian to active guardian. Move ALL items,
     * in the case of semi-fungibles. Must pass a guardian classe for each item for the new guardian.
     *
     * Requirements:
     *
     * 1) The caller must be 4K.
     * 2) Old guardian must be inactive.
     * 3) New guardian must be active.
     * 4) Each class passed for each item for the new guardian must be active.
     * 5) Must only be used to move ALL items and have movement of guardian fees after moving ALL items.
     * @param collection Address of the collection that includes the items being moved.
     * @param ids Array of item ids being moved.
     * @param oldGuardian Address of the guardian items are being moved from.
     * @param newGuardian Address of the guardian items are being moved to.
     * @param newGuardianClassIndeces Array of the newGuardian's guardian class indices the items will be moved to.
     */
    function moveItems(
        IERC11554K collection,
        uint256[] calldata ids,
        address oldGuardian,
        address newGuardian,
        uint256[] calldata newGuardianClassIndeces
    ) external virtual onlyOwner {
        if (isAvailable(oldGuardian)) {
            revert OldGuardianAvailable();
        }
        if (!isAvailable(newGuardian)) {
            revert NewGuardianUnavailable();
        }
        for (uint256 i = 0; i < ids.length; ++i) {
            if (!isClassActive(newGuardian, newGuardianClassIndeces[i])) {
                revert ClassNotActive();
            }
            _moveSingleItem(
                collection,
                ids[i],
                oldGuardian,
                newGuardian,
                newGuardianClassIndeces[i]
            );
        }
    }

    /**
     * @notice Copies all guardian classes from one guardian to another.
     * @dev If new guardian has no guardian classes before this, class indeces will be the same. If not, copies classes will have new indeces.
     *
     * @param oldGuardian Address of the guardian whose classes will be moved.
     * @param newGuardian Address of the guardian that will be receiving the classes.
     */
    function copyGuardianClasses(
        address oldGuardian,
        address newGuardian
    ) external virtual onlyOwner {
        for (uint256 i = 0; i < guardiansClasses[oldGuardian].length; i++) {
            _copyGuardianClass(oldGuardian, newGuardian, i);
        }
    }

    /**
     * @notice Function for the guardian to set item(s) to be flagged for repossession.
     * @param collection Collection that contains the item to be repossessed.
     * @param itemId Id of item(s) being reposessed.
     * @param owner Current owner of the item(s).
     */
    function setItemsToRepossessed(
        IERC11554K collection,
        uint256 itemId,
        address owner
    ) external {
        if (whereItemStored[collection][itemId] != _msgSender()) {
            revert NotGuardianOfItems();
        }
        if (getGuardianFeeRateByCollectionItem(collection, itemId) == 0) {
            revert FreeStorageItemsCantBeRepossessed();
        }
        if (
            guardianFeePaidUntil[owner][collection][itemId] >= block.timestamp
        ) {
            revert GuardianFeePaidUntilStillInFuture();
        }

        uint256 currAmount = IERC11554K(collection).balanceOf(owner, itemId);
        if (currAmount == 0) {
            revert NoItemsToRepossess();
        }

        uint256 prevInReposession = inRepossession[owner][collection][itemId];
        inRepossession[owner][collection][itemId] = currAmount;

        emit SetForRepossession(
            itemId,
            collection,
            _msgSender(),
            currAmount - prevInReposession
        );
    }

    /**
     * @notice Sets activity mode for the guardian. Either active or not.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose activity mode will be set.
     * @param activity Boolean for guardian activity mode.
     */
    function setActivity(
        address guardian,
        bool activity
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].isActive = activity;
        emit GuardianModified(guardian, 5, guardianInfo[guardian]);
    }

    /**
     * @notice Sets privacy mode for the guardian. Either public false or private true.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose privacy mode will be set.
     * @param privacy Boolean for guardian privacy mode.
     */
    function setPrivacy(
        address guardian,
        bool privacy
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].isPrivate = privacy;
        emit GuardianModified(guardian, 4, guardianInfo[guardian]);
    }

    /**
     * @notice Sets logo for the guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian address of guardian whose logo will be set.
     * @param logo URI of logo for guardian.
     */
    function setLogo(
        address guardian,
        string calldata logo
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].logo = logo;
        emit GuardianModified(guardian, 1, guardianInfo[guardian]);
    }

    /**
     * @notice Sets name for the guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose name will be set.
     * @param name Name of guardian.
     */
    function setName(
        address guardian,
        string calldata name
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].name = name;
        emit GuardianModified(guardian, 2, guardianInfo[guardian]);
    }

    /**
     * @notice Sets physical address hash for the guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose physical address will be set.
     * @param physicalAddressHash Bytes hash of physical address of the guardian.
     */
    function setPhysicalAddressHash(
        address guardian,
        bytes32 physicalAddressHash
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].addressHash = physicalAddressHash;
        emit GuardianModified(guardian, 0, guardianInfo[guardian]);
    }

    /**
     * @notice Sets policy for the guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose policy will be set.
     * @param policy Guardian policy.
     */
    function setPolicy(
        address guardian,
        string calldata policy
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].policy = policy;
        emit GuardianModified(guardian, 4, guardianInfo[guardian]);
    }

    /**
     * @notice Sets redirects for the guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose redirect URI will be set.
     * @param redirect Redirect URI for guardian.
     */
    function setRedirect(
        address guardian,
        string calldata redirect
    ) external onlyWhitelisted(guardian) ifNotOwnerGuardianIsCaller(guardian) {
        guardianInfo[guardian].redirect = redirect;
        emit GuardianModified(guardian, 3, guardianInfo[guardian]);
    }

    /**
     * @notice Adds or removes users addresses to guardian whitelist.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian whose users whitelist status will be modified.
     * @param users Array of user addresses whose whitelist status will be modified.
     * @param whitelistStatus Boolean for the whitelisted status of the users.
     */
    function changeWhitelistUsersStatus(
        address guardian,
        address[] calldata users,
        bool whitelistStatus
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        for (uint256 i = 0; i < users.length; ++i) {
            guardianWhitelist[guardian][users[i]] = whitelistStatus;
        }
    }

    /**
     * @notice Removes guardian from the whitelist.
     *
     * Requirements:
     *
     * 1) The caller must be a contract owner.
     * @param guardian address of guardian who will be removed.
     */
    function removeGuardian(address guardian) external virtual onlyOwner {
        isWhitelisted[guardian] = false;
        guardianInfo[guardian].isActive = false;
        emit GuardianRemoved(guardian);
    }

    /**
     * @notice Sets minting fee for guardian class by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or the owner.
     * @param guardian Address of the guardian whose guardian class minting fee will be modified.
     * @param classID Guardian's guardian class index whose minting fee will be modified.
     * @param mintingFee New minting fee. Minting fee must be passed as already scaled by 10^18 from real life value.
     */
    function setGuardianClassMintingFee(
        address guardian,
        uint256 classID,
        uint256 mintingFee
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        if (mintingFee < minimumRequestFee) {
            revert MintingFeeTooLow();
        }
        guardiansClasses[guardian][classID].mintingFee = mintingFee;
        emit GuardianClassModified(
            guardian,
            classID,
            1,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @notice Sets redemption fee for guardian class by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or the owner
     * @param guardian Address of the guardian whose guardian class redemption fee will be modified.
     * @param classID Guardian's guardian class index whose redemption fee will be modified.
     * @param redemptionFee New redemption fee. Redemption fee must be passed as already scaled by 10^18 from real life value.
     */
    function setGuardianClassRedemptionFee(
        address guardian,
        uint256 classID,
        uint256 redemptionFee
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        guardiansClasses[guardian][classID].redemptionFee = redemptionFee;
        emit GuardianClassModified(
            guardian,
            classID,
            2,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @notice Sets Guardian fee rate for guardian class by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or the owner.
     * @param guardian Address of the guardian whose guardian class guardian fee rate will be modified.
     * @param classID Guardian's guardian class index whose guardian fee rate  will be modified.
     * @param guardianFeeRate New guardian fee rate. Guardain fee rate must be passed as already scaled by 10^18 from real life value.
     */
    function setGuardianClassGuardianFeeRate(
        address guardian,
        uint256 classID,
        uint256 guardianFeeRate
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        _setGuardianClassGuardianFeeRate(
            guardian,
            classID,
            guardianFeeRate,
            guardiansClasses[guardian][classID].guardianFeeRatePeriod
        );
    }

    /**
     * @notice Sets Guardian fee rate and guardian fee rate period for guardian class by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or the owner.
     * @param guardian Address of the guardian whose guardian class guardian fee rate will be modified.
     * @param classID Guardian's guardian class index whose guardian fee rate  will be modified.
     * @param guardianFeeRatePeriod New guardian fee rate period.
     * @param guardianFeeRate New guardian fee rate. Guardain fee rate must be passed as already scaled by 10^18 from real life value.
     */
    function setGuardianClassGuardianFeePeriodAndRate(
        address guardian,
        uint256 classID,
        GuardianFeeRatePeriods guardianFeeRatePeriod,
        uint256 guardianFeeRate
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        uint256 newPeriodMultiple;
        if (guardianFeeRatePeriod == GuardianFeeRatePeriods.SECONDS) {
            newPeriodMultiple = SECOND;
        } else if (guardianFeeRatePeriod == GuardianFeeRatePeriods.MINUTES) {
            newPeriodMultiple = MINUTE;
        } else if (guardianFeeRatePeriod == GuardianFeeRatePeriods.HOURS) {
            newPeriodMultiple = HOUR;
        } else if (guardianFeeRatePeriod == GuardianFeeRatePeriods.DAYS) {
            newPeriodMultiple = DAY;
        }
        if (
            guardiansClasses[guardian][classID].guardianFeeRatePeriod ==
            newPeriodMultiple
        ) {
            revert DifferentPeriodRequired();
        }
        _setGuardianClassGuardianFeeRate(
            guardian,
            classID,
            guardianFeeRate,
            newPeriodMultiple
        );

        guardiansClasses[guardian][classID]
            .guardianFeeRatePeriod = newPeriodMultiple;
        emit GuardianClassModified(
            guardian,
            classID,
            3,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @notice Sets URI for guardian class by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or owner.
     * @param guardian Address of the guardian whose guardian class URI will be modified.
     * @param classID Guardian's guardian class index whose class URI will be modified.
     * @param uri New URI.
     */
    function setGuardianClassURI(
        address guardian,
        uint256 classID,
        string calldata uri
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        guardiansClasses[guardian][classID].uri = uri;
        emit GuardianClassModified(
            guardian,
            classID,
            8,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @notice Sets guardian class as active or not active by guardian or owner
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or owner.
     * @param guardian Address of the guardian whose guardian class active status will be modified.
     * @param classID Guardian's guardian class index whose guardian class active status will be modified.
     * @param activeStatus New guardian class active status.
     */
    function setGuardianClassActiveStatus(
        address guardian,
        uint256 classID,
        bool activeStatus
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        guardiansClasses[guardian][classID].isActive = activeStatus;
        emit GuardianClassModified(
            guardian,
            classID,
            7,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @notice Sets maximum insurance coverage for guardian class by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian.
     * @param guardian Address of the guardian whose guardian class maximum coverage will be modified.
     * @param classID Guardian's guardian class index whose guardian class maximum coverage will be modified.
     * @param maximumCoverage New guardian class maximum coverage.
     */
    function setGuardianClassMaximumCoverage(
        address guardian,
        uint256 classID,
        uint256 maximumCoverage
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
    {
        guardiansClasses[guardian][classID].maximumCoverage = maximumCoverage;
        emit GuardianClassModified(
            guardian,
            classID,
            0,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @dev Sets the version of the contract.
     * @param version_ New version of contract.
     */
    function setVersion(bytes32 version_) external virtual onlyOwner {
        version = version_;
    }

    /**
     * @dev Externally called store item function by controller to update Guardian fees on token transfer. Complex logic needed for semi-fungibles.
     * @param from Address of entity sending token(s).
     * @param to Address of entity receiving token(s).
     * @param id Token id of token(s) being sent.
     * @param amount Amount of tokens being sent.
     */
    function shiftGuardianFeesOnTokenMove(
        address from,
        address to,
        uint256 id,
        uint256 amount
    ) external virtual {
        if (
            !controller.isActiveCollection(_msgSender()) ||
            !controller.isLinkedCollection(_msgSender())
        ) {
            revert CollectionIsNotActiveOrLinked();
        }
        IERC11554K collection = IERC11554K(_msgSender());

        uint256 guardianClassFeeRate = getGuardianFeeRateByCollectionItem(
            collection,
            id
        );

        uint256 guardianClassFeeRatePeriod = getGuardianFeeRatePeriodByCollectionItem(
                collection,
                id
            );

        uint256 guardianFeeShiftAmount = GuardianTimeMath
            .calculateRemainingFeeAmount(
                guardianFeePaidUntil[from][collection][id],
                guardianClassFeeRate,
                guardianClassFeeRatePeriod,
                amount
            );

        uint256 remainingFeeAmountFrom = GuardianTimeMath
            .calculateRemainingFeeAmount(
                guardianFeePaidUntil[from][collection][id],
                guardianClassFeeRate,
                guardianClassFeeRatePeriod,
                collection.balanceOf(from, id)
            );

        uint256 remainingFeeAmountTo = GuardianTimeMath
            .calculateRemainingFeeAmount(
                guardianFeePaidUntil[to][collection][id],
                guardianClassFeeRate,
                guardianClassFeeRatePeriod,
                collection.balanceOf(to, id)
            );

        // Recalculate the remaining time with new params for FROM
        uint256 newAmountFrom = collection.balanceOf(from, id) - amount;
        if (newAmountFrom == 0) {
            guardianFeePaidUntil[from][collection][id] = 0; //default
        } else {
            guardianFeePaidUntil[from][collection][id] =
                block.timestamp +
                GuardianTimeMath.calculateAddedGuardianTime(
                    remainingFeeAmountFrom - guardianFeeShiftAmount,
                    guardianClassFeeRate,
                    guardianClassFeeRatePeriod,
                    newAmountFrom
                );
        }

        // Recalculate the remaining time with new params for TO
        uint256 newAmountTo = collection.balanceOf(to, id) + amount;
        guardianFeePaidUntil[to][collection][id] =
            block.timestamp +
            GuardianTimeMath.calculateAddedGuardianTime(
                remainingFeeAmountTo + guardianFeeShiftAmount,
                guardianClassFeeRate,
                guardianClassFeeRatePeriod,
                newAmountTo
            );
    }

    /**
     * @notice Adds guardian class to guardian by guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a whitelisted guardian or contract owner.
     * @param guardian Address of guardian who is adding a new class.
     * @param maximumCoverage Max coverage of new guardian class.
     * @param mintingFee Minting fee of new guardian class. Minting fee must be passed as already scaled by 10^18 from real life value.
     * @param redemptionFee Redemption fee of new guardian class. Redemption fee must be passed as already scaled by 10^18 from real life value.
     * @param guardianFeeRate Guardian fee rate of new guardian class. Guardian fee rate must be passed as already scaled by 10^18 from real life value.
     * @param guardianFeeRatePeriod The size of the period unit for the guardian fee rate: per second, minute, hour, or day.
     */
    function addGuardianClass(
        address guardian,
        uint256 maximumCoverage,
        uint256 mintingFee,
        uint256 redemptionFee,
        uint256 guardianFeeRate,
        GuardianFeeRatePeriods guardianFeeRatePeriod,
        string calldata uri
    )
        external
        virtual
        onlyWhitelisted(guardian)
        ifNotOwnerGuardianIsCaller(guardian)
        returns (uint256 classID)
    {
        classID = _addGuardianClass(
            guardian,
            maximumCoverage,
            mintingFee,
            redemptionFee,
            guardianFeeRate,
            guardianFeeRatePeriod,
            uri
        );
    }

    /**
     * @notice Registers guardian.
     *
     * Requirements:
     *
     * 1) The caller must be a contract owner.
     * @param guardian Address of the new guardian.
     * @param name Name of new guardian.
     * @param logo URI of new guardian logo.
     * @param policy Policy of new guardian.
     * @param redirect Redirect URI of new guardian.
     * @param physicalAddressHash physical address hash of new guardian.
     * @param privacy Boolean - is the new guardian private or not.
     */
    function registerGuardian(
        address guardian,
        string calldata name,
        string calldata logo,
        string calldata policy,
        string calldata redirect,
        bytes32 physicalAddressHash,
        bool privacy
    ) external virtual {
        guardianInfo[guardian].isActive = true;
        guardianInfo[guardian].name = name;
        guardianInfo[guardian].logo = logo;
        guardianInfo[guardian].policy = policy;
        guardianInfo[guardian].isPrivate = privacy;
        guardianInfo[guardian].redirect = redirect;
        guardianInfo[guardian].addressHash = physicalAddressHash;
        addGuardian(guardian);
        emit GuardianRegistered(guardian, guardianInfo[guardian]);
    }

    /**
     * @notice Delegates whole minting/redemption for all or single collection to `delegatee`
     * @param delegatee Address to which the calling guardian will delegate to.
     * @param collection If not zero address, then delegates processes only for this collection.
     */
    function delegate(
        address delegatee,
        IERC11554K collection
    ) external virtual onlyWhitelisted(_msgSender()) {
        if (address(collection) == address(0)) {
            delegatedAll[_msgSender()][delegatee] = true;
        } else {
            delegatedCollection[_msgSender()][collection] = delegatee;
        }
    }

    /**
     * @notice Undelegates whole minting/redemption for all or single collection from `delegatee`
     * @param delegatee Address to which the calling guardian will undelegate from.
     * @param collection If not zero address, then undelegates processes only for this collection.
     */
    function undelegate(
        address delegatee,
        IERC11554K collection
    ) external virtual onlyWhitelisted(_msgSender()) {
        if (address(collection) == address(0)) {
            delegatedAll[_msgSender()][delegatee] = false;
        } else {
            delegatedCollection[_msgSender()][collection] = address(0);
        }
    }

    /**
     * @notice Queries if the amount of guardian fee provided purchases the minimum guardian time for a particular guardian class.
     * @param guardianFeeAmount the amount of guardian fee being queried.
     * @param numItems Number of total items the guardian would be storing.
     * @param guardian Address of the guardian that would be doing the storing.
     * @param guardianClassIndex Index of guardian class that would be doing the storing.
     */
    function isFeeAboveMinimum(
        uint256 guardianFeeAmount,
        uint256 numItems,
        address guardian,
        uint256 guardianClassIndex
    ) external view virtual returns (bool) {
        uint256 guardianClassFeeRate = getGuardianFeeRate(
            guardian,
            guardianClassIndex
        );
        uint256 guardianFeeRatePeriod = getGuardianFeeRatePeriod(
            guardian,
            guardianClassIndex
        );

        if (guardianClassFeeRate == 0) {
            revert GuardianClassFeeRateTooLow();
        }

        return
            minStorageTime <=
            GuardianTimeMath.calculateAddedGuardianTime(
                guardianFeeAmount,
                guardianClassFeeRate,
                guardianFeeRatePeriod,
                numItems
            );
    }

    /**
     * @notice Returns guardian class redemption fee.
     * @param guardian Address of guardian whose guardian class is being queried.
     * @param classID Guardian's guardian class index being queried.
     * @return redemptionFee Guardian class's redemption fee. Returns scaled by 10^18 real life value.
     */
    function getRedemptionFee(
        address guardian,
        uint256 classID
    ) external view virtual returns (uint256) {
        return guardiansClasses[guardian][classID].redemptionFee;
    }

    /**
     * @notice Returns guardian class minting fee.
     * @param guardian Address of guardian whose guardian class is being queried.
     * @param classID Guardian's guardian class index being queried.
     * @return mintingFee Guardian class's minting fee. Returns scaled by 10^18 real life value.
     */
    function getMintingFee(
        address guardian,
        uint256 classID
    ) external view virtual returns (uint256) {
        return guardiansClasses[guardian][classID].mintingFee;
    }

    /**
     * @notice Returns guardian classes number.
     * @param guardian Address of guardian whose guardian classes are being queried.
     * @return count How many guardian classes the guardian has.
     */
    function guardianClassesCount(
        address guardian
    ) external view virtual returns (uint256) {
        return guardiansClasses[guardian].length;
    }

    /**
     * @notice Checks if delegator delegated collection handling to delegatee.
     * @param collection Delegator guardian address.
     * @param delegatee Delegatee address.
     * @param collection Collection address.
     * @return true if delegated, false otherwise.
     */
    function isDelegated(
        address delegator,
        address delegatee,
        IERC11554K collection
    ) external view virtual returns (bool) {
        return
            delegatedCollection[delegator][collection] == delegatee ||
            delegatedAll[delegator][delegatee];
    }

    /**
     * @notice Adds guardian to the whitelist.
     *
     * Requirements:
     *
     * 1) The caller must be a contract owner.
     * @param guardian Address of the new guardian.
     */
    function addGuardian(address guardian) public virtual onlyOwner {
        isWhitelisted[guardian] = true;
        guardianInfo[guardian].isActive = true;
        emit GuardianAdded(guardian, guardianInfo[guardian]);
    }

    /**
     * @notice Anyone can add Guardian fees to a guardian holding an item.
     * @param collection Address of the collection the item belongs to.
     * @param beneficiary The address of the holder of the item.
     * @param itemId Id of the item.
     * @param guardianFeeAmount The amount of guardian fee being paid.
     */
    function addStorageTime(
        IERC11554K collection,
        address beneficiary,
        uint256 itemId,
        uint256 guardianFeeAmount
    ) public virtual {
        uint256 currAmount = collection.balanceOf(beneficiary, itemId);

        address guardian = whereItemStored[collection][itemId];
        uint256 guardianClassIndex = itemGuardianClass[collection][itemId];

        uint256 guardianClassFeeRate = getGuardianFeeRate(
            guardian,
            guardianClassIndex
        );
        if (guardianClassFeeRate == 0) {
            revert GuardianClassFeeRateTooLow();
        }
        if (guardianFeeAmount == 0) {
            revert GuardianFeeTooLow();
        }
        if (currAmount == 0) {
            revert BeneficiaryDoesNotOwnItem();
        }
        if (guardian == address(0)) {
            revert GuardianDoesNotStoreItem();
        }
        {
            uint256 addedStorageTime = GuardianTimeMath
                .calculateAddedGuardianTime(
                    guardianFeeAmount,
                    guardianClassFeeRate,
                    getGuardianFeeRatePeriod(guardian, guardianClassIndex),
                    currAmount
                );

            guardianFeePaidUntil[beneficiary][collection][
                itemId
            ] += addedStorageTime;
            emit StorageTimeAdded(
                itemId,
                guardian,
                addedStorageTime,
                beneficiary,
                collection
            );
        }

        feesManager.payGuardianFee(
            guardianFeeAmount,
            (guardianClassFeeRate * currAmount) /
                getGuardianFeeRatePeriod(guardian, guardianClassIndex),
            guardian,
            guardianFeePaidUntil[beneficiary][collection][itemId],
            _msgSender(),
            controller.paymentToken()
        );
    }

    /**
     * @notice Returns guardian class guardian fee rate of the stored item in collection with  itemId.
     * @param collection Address of the collection where the item being queried belongs to.
     * @param itemId Item id of item whose guardian fee rate is being queried.
     * @return guardianFeeRate Fee rate of the item being queried (of guardian class it's in). Returns scaled by 10^18 real life value.
     */
    function getGuardianFeeRateByCollectionItem(
        IERC11554K collection,
        uint256 itemId
    ) public view virtual returns (uint256) {
        if (collection.totalSupply(itemId) == 0) {
            revert ItemNotYetMinted();
        }
        return
            guardiansClasses[whereItemStored[collection][itemId]][
                itemGuardianClass[collection][itemId]
            ].guardianFeeRate;
    }

    /**
     * @notice Returns guardian class guardian fee rate period size of the stored item in collection with  itemId.
     * @param collection Address of the collection where the item being queried belongs to.
     * @param itemId Item id of item whose guardian fee rate is being queried.
     * @return guardianFeeRatePeriod Size of the item being queried (of guardian class it's in).
     */
    function getGuardianFeeRatePeriodByCollectionItem(
        IERC11554K collection,
        uint256 itemId
    ) public view virtual returns (uint256) {
        if (collection.totalSupply(itemId) == 0) {
            revert ItemNotYetMinted();
        }
        return
            guardiansClasses[whereItemStored[collection][itemId]][
                itemGuardianClass[collection][itemId]
            ].guardianFeeRatePeriod;
    }

    /**
     * @notice Returns true if the guardian is active and whitelisted.
     * @param guardian Address of guardian whose guardian class is being queried.
     * @return boolean Is the guardian active and whitelisted.
     */
    function isAvailable(address guardian) public view returns (bool) {
        return isWhitelisted[guardian] && guardianInfo[guardian].isActive;
    }

    /**
     * @notice Returns guardian class classID guardian fee rate.
     * @param guardian Address of guardian whose guardian class is being queried.
     * @param classID Guardian's class index for class being queried.
     * @return guardianFeeRate The guardian class guardian fee rate. Returns scaled by 10^18 real life value.
     */
    function getGuardianFeeRate(
        address guardian,
        uint256 classID
    ) public view virtual returns (uint256) {
        return guardiansClasses[guardian][classID].guardianFeeRate;
    }

    /**
     * @notice Returns guardian class classID guardian fee rate period size.
     * @param guardian Address of guardian whose guardian class is being queried.
     * @param classID Guardian's class index for class being queried.
     * @return guardianFeeRatePeriod The unit of time for the guardian fee rate.
     */
    function getGuardianFeeRatePeriod(
        address guardian,
        uint256 classID
    ) public view virtual returns (uint256) {
        return guardiansClasses[guardian][classID].guardianFeeRatePeriod;
    }

    /**
     * @notice Returns guardian class classID activity true/false.
     * @param guardian Address of guardian whose guardian class is being queried.
     * @param classID Guardian's class index for class being queried.
     * @return activeStatus Boolean - is the class active or not.
     */
    function isClassActive(
        address guardian,
        uint256 classID
    ) public view virtual returns (bool) {
        return guardiansClasses[guardian][classID].isActive;
    }

    /**
     * @dev Internal call, adds guardian class.
     */
    function _addGuardianClass(
        address guardian,
        uint256 maximumCoverage,
        uint256 mintingFee,
        uint256 redemptionFee,
        uint256 guardianFeeRate,
        GuardianFeeRatePeriods guardianFeeRatePeriod,
        string calldata uri
    ) internal virtual returns (uint256 classID) {
        classID = guardiansClasses[guardian].length;

        uint256 periodMultiple;
        if (guardianFeeRatePeriod == GuardianFeeRatePeriods.SECONDS) {
            periodMultiple = SECOND;
        } else if (guardianFeeRatePeriod == GuardianFeeRatePeriods.MINUTES) {
            periodMultiple = MINUTE;
        } else if (guardianFeeRatePeriod == GuardianFeeRatePeriods.HOURS) {
            periodMultiple = HOUR;
        } else if (guardianFeeRatePeriod == GuardianFeeRatePeriods.DAYS) {
            periodMultiple = DAY;
        }

        guardiansClasses[guardian].push(
            GuardianClass(
                maximumCoverage,
                mintingFee,
                redemptionFee,
                periodMultiple,
                guardianFeeRate,
                guardianFeeRate,
                block.timestamp,
                true,
                uri
            )
        );
        emit GuardianClassAdded(
            guardian,
            classID,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @dev Internal call, copies an ENTIRE guardian class from one guardian to another. Note: same data but DIFFERENT index.
     */
    function _copyGuardianClass(
        address oldGuardian,
        address newGuardian,
        uint256 oldGuardianClassIndex
    ) internal returns (uint256 classID) {
        classID = guardiansClasses[newGuardian].length;
        guardiansClasses[newGuardian].push(
            GuardianClass(
                guardiansClasses[oldGuardian][oldGuardianClassIndex]
                    .maximumCoverage,
                guardiansClasses[oldGuardian][oldGuardianClassIndex].mintingFee,
                guardiansClasses[oldGuardian][oldGuardianClassIndex]
                    .redemptionFee,
                guardiansClasses[oldGuardian][oldGuardianClassIndex]
                    .guardianFeeRatePeriod,
                guardiansClasses[oldGuardian][oldGuardianClassIndex]
                    .guardianFeeRate,
                guardiansClasses[oldGuardian][oldGuardianClassIndex]
                    .guardianFeeRateMinimum,
                guardiansClasses[oldGuardian][oldGuardianClassIndex]
                    .lastGuardianFeeRateIncrease,
                guardiansClasses[oldGuardian][oldGuardianClassIndex].isActive,
                guardiansClasses[oldGuardian][oldGuardianClassIndex].uri
            )
        );
        emit GuardianClassAdded(
            newGuardian,
            classID,
            guardiansClasses[newGuardian][classID]
        );
    }

    /**
     * @dev Internal call, sets a new guardian class guardian fee rate, with several checks. Compensates for a different period multiple
     */
    function _setGuardianClassGuardianFeeRate(
        address guardian,
        uint256 classID,
        uint256 guardianFeeRate,
        uint256 newPeriodMultiple
    ) internal virtual {
        if (guardianFeeRate == 0) {
            revert GuardianClassFeeRateTooLow();
        }

        if (guardiansClasses[guardian][classID].guardianFeeRate == 0) {
            revert GuardianFeeNotChangeableOnFreeStorageClass();
        }

        uint256 currentPeriodMultiple = guardiansClasses[guardian][classID]
            .guardianFeeRatePeriod;
        if (
            (guardianFeeRate / newPeriodMultiple) >
            (guardiansClasses[guardian][classID].guardianFeeRate /
                currentPeriodMultiple)
        ) {
            if (
                block.timestamp <
                guardiansClasses[guardian][classID]
                    .lastGuardianFeeRateIncrease +
                    guardianFeeSetWindow
            ) {
                revert GuardianFeeWindowHasntPassed();
            }

            if (
                (guardianFeeRate / newPeriodMultiple) >
                (guardiansClasses[guardian][classID].guardianFeeRate *
                    maximumGuardianFeeSet) /
                    (currentPeriodMultiple * PERCENTAGE_FACTOR)
            ) {
                revert GuardianFeeRateLimitExceeded();
            }

            guardiansClasses[guardian][classID]
                .lastGuardianFeeRateIncrease = block.timestamp;
        }
        guardiansClasses[guardian][classID].guardianFeeRate = guardianFeeRate;
        if (
            (guardianFeeRate / newPeriodMultiple) <
            (guardiansClasses[guardian][classID].guardianFeeRateMinimum /
                currentPeriodMultiple)
        ) {
            guardiansClasses[guardian][classID]
                .guardianFeeRateMinimum = guardianFeeRate;
        }
        emit GuardianClassModified(
            guardian,
            classID,
            4,
            guardiansClasses[guardian][classID]
        );
    }

    /**
     * @dev Internal call that is done on each item token redeem to
     * relaculate paid storage time, guardian fees.
     */
    function _shiftGuardianFeesOnTokenRedeem(
        address from,
        IERC11554K collection,
        uint256 id,
        uint256 redeemAmount,
        uint256 guardianClassFeeRate,
        uint256 guardianFeeRatePeriod
    ) internal virtual returns (uint256) {
        // Recalculate the remaining time with new params
        uint256 bal = IERC11554K(collection).balanceOf(from, id);
        // Total fee that remains
        uint256 remainingFeeAmount = GuardianTimeMath
            .calculateRemainingFeeAmount(
                guardianFeePaidUntil[from][collection][id],
                guardianClassFeeRate,
                guardianFeeRatePeriod,
                bal
            );

        // Portion of fee we're giving back, for refund.
        uint256 guardianFeeRefundAmount = GuardianTimeMath
            .calculateRemainingFeeAmount(
                guardianFeePaidUntil[from][collection][id],
                guardianClassFeeRate,
                guardianFeeRatePeriod,
                redeemAmount
            );

        if (bal - redeemAmount == 0) {
            guardianFeePaidUntil[from][collection][id] = 0; //back to default,0
        } else {
            uint256 recalculatedTime = GuardianTimeMath
                .calculateAddedGuardianTime(
                    remainingFeeAmount - guardianFeeRefundAmount,
                    guardianClassFeeRate,
                    guardianFeeRatePeriod,
                    bal - redeemAmount
                );
            guardianFeePaidUntil[from][collection][id] =
                block.timestamp +
                recalculatedTime;
        }
        return guardianFeeRefundAmount;
    }

    function _moveSingleItem(
        IERC11554K collection,
        uint256 itemId,
        address oldGuardian,
        address newGuardian,
        uint256 newGuardianClassIndex
    ) internal virtual {
        uint256 amount = stored[oldGuardian][collection][itemId];
        stored[oldGuardian][collection][itemId] = 0;
        stored[newGuardian][collection][itemId] += amount;
        whereItemStored[collection][itemId] = newGuardian;
        itemGuardianClass[collection][itemId] = newGuardianClassIndex;

        emit ItemMoved(
            oldGuardian,
            newGuardian,
            newGuardianClassIndex,
            itemId,
            collection
        );
    }
}

File 2 of 11 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.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 OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(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");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 3 of 11 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 4 of 11 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 5 of 11 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

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

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 6 of 11 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @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 ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 7 of 11 : IERC11554K.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "./IGuardians.sol";

/**
 * @dev {IERC11554K} interface:
 */
interface IERC11554K {
    function controllerMint(
        address mintAddress,
        uint256 tokenId,
        uint256 amount
    ) external;

    function controllerBurn(
        address burnAddress,
        uint256 tokenId,
        uint256 amount
    ) external;

    function setGuardians(IGuardians guardians_) external;

    function setURI(string calldata newuri) external;

    function setCollectionURI(string calldata collectionURI_) external;

    function setVerificationStatus(bool _isVerified) external;

    function setGlobalRoyalty(address receiver, uint96 feeNumerator) external;

    function owner() external view returns (address);

    function balanceOf(
        address user,
        uint256 item
    ) external view returns (uint256);

    function royaltyInfo(
        uint256 _tokenId,
        uint256 _salePrice
    ) external view returns (address, uint256);

    function totalSupply(uint256 _tokenId) external view returns (uint256);
}

File 8 of 11 : IERC11554KController.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "./IERC11554K.sol";
import "./IGuardians.sol";

/**
 * @dev {IERC11554KController} interface:
 */
interface IERC11554KController {
    /// @dev Batch minting request data structure.
    struct BatchRequestMintData {
        /// @dev Collection address.
        IERC11554K collection;
        /// @dev Item id.
        uint256 id;
        /// @dev Guardian address.
        address guardianAddress;
        /// @dev Amount to mint.
        uint256 amount;
        /// @dev Service fee to guardian.
        uint256 serviceFee;
        /// @dev Is item supply expandable.
        bool isExpandable;
        /// @dev Recipient address.
        address mintAddress;
        /// @dev Guardian class index.
        uint256 guardianClassIndex;
        /// @dev Guardian fee amount to pay.
        uint256 guardianFeeAmount;
    }

    function requestMint(
        IERC11554K collection,
        uint256 id,
        address guardian,
        uint256 amount,
        uint256 serviceFee,
        bool expandable,
        address mintAddress,
        uint256 guardianClassIndex,
        uint256 guardianFeeAmount
    ) external returns (uint256);

    function mint(IERC11554K collection, uint256 id) external;

    function owner() external returns (address);

    function originators(
        address collection,
        uint256 tokenId
    ) external returns (address);

    function isActiveCollection(address collection) external returns (bool);

    function isLinkedCollection(address collection) external returns (bool);

    function paymentToken() external returns (IERC20Upgradeable);

    function maxMintPeriod() external returns (uint256);

    function remediationBurn(
        IERC11554K collection,
        address owner,
        uint256 id,
        uint256 amount
    ) external;

    function setMaxMintPeriod(uint256 maxMintPeriod_) external;

    function setRemediator(address _remediator) external;

    function setCollectionFee(uint256 collectionFee_) external;

    function setBeneficiary(address beneficiary_) external;

    function setGuardians(IGuardians guardians_) external;

    function setPaymentToken(IERC20Upgradeable paymentToken_) external;

    function transferOwnership(address newOwner) external;

    function setVersion(bytes32 version_) external;

    function guardians() external view returns (address);
}

File 9 of 11 : IFeesManager.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "./IERC11554K.sol";
import "./IGuardians.sol";
import "./IERC11554KController.sol";

/**
 * @dev {IFeesManager} interface:
 */
interface IFeesManager {
    function receiveFees(
        IERC11554K erc11554k,
        uint256 id,
        IERC20Upgradeable asset,
        uint256 _salePrice
    ) external;

    function calculateTotalFee(
        IERC11554K erc11554k,
        uint256 id,
        uint256 _salePrice
    ) external returns (uint256);

    function payGuardianFee(
        uint256 guardianFeeAmount,
        uint256 guardianClassFeeRateMultiplied,
        address guardian,
        uint256 storagePaidUntil,
        address payer,
        IERC20Upgradeable paymentAsset
    ) external;

    function refundGuardianFee(
        uint256 guardianFeeAmount,
        uint256 guardianClassFeeRateMultiplied,
        address guardian,
        uint256 storagePaidUntil,
        address recipient,
        IERC20Upgradeable paymentAsset
    ) external;

    function moveFeesBetweenGuardians(
        address guardianFrom,
        address guardianTo,
        IERC20Upgradeable asset
    ) external;

    function setGuardians(IGuardians guardians_) external;

    function setController(IERC11554KController controller_) external;

    function setGlobalTradingFee(uint256 globalTradingFee_) external;

    function setTradingFeeSplit(
        uint256 protocolSplit,
        uint256 guardianSplit
    ) external;

    function setExchange(address exchange_) external;

    function setVersion(bytes32 version_) external;

    function transferOwnership(address newOwner) external;
}

File 10 of 11 : IGuardians.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "./IERC11554K.sol";
import "./IERC11554KController.sol";
import "./IFeesManager.sol";

/**
 * @dev {IGuardians} interface:
 */
interface IGuardians {
    enum GuardianFeeRatePeriods {
        SECONDS,
        MINUTES,
        HOURS,
        DAYS
    }

    function controllerStoreItem(
        IERC11554K collection,
        address mintAddress,
        uint256 id,
        address guardian,
        uint256 guardianClassIndex,
        uint256 guardianFeeAmount,
        uint256 numItems,
        address feePayer,
        IERC20Upgradeable paymentAsset
    ) external;

    function controllerTakeItemOut(
        address guardian,
        IERC11554K collection,
        uint256 id,
        uint256 numItems,
        address from
    ) external;

    function shiftGuardianFeesOnTokenMove(
        address from,
        address to,
        uint256 id,
        uint256 amount
    ) external;

    function setController(IERC11554KController controller_) external;

    function setFeesManager(IFeesManager feesManager_) external;

    function setMinStorageTime(uint256 minStorageTime_) external;

    function setMinimumRequestFee(uint256 minimumRequestFee_) external;

    function setMaximumGuardianFeeSet(uint256 maximumGuardianFeeSet_) external;

    function setGuardianFeeSetWindow(uint256 guardianFeeSetWindow_) external;

    function moveItems(
        IERC11554K collection,
        uint256[] calldata ids,
        address oldGuardian,
        address newGuardian,
        uint256[] calldata newGuardianClassIndeces
    ) external;

    function copyGuardianClasses(
        address oldGuardian,
        address newGuardian
    ) external;

    function setActivity(address guardian, bool activity) external;

    function setPrivacy(address guardian, bool privacy) external;

    function setLogo(address guardian, string calldata logo) external;

    function setName(address guardian, string calldata name) external;

    function setPhysicalAddressHash(
        address guardian,
        bytes32 physicalAddressHash
    ) external;

    function setPolicy(address guardian, string calldata policy) external;

    function setRedirect(address guardian, string calldata redirect) external;

    function changeWhitelistUsersStatus(
        address guardian,
        address[] calldata users,
        bool whitelistStatus
    ) external;

    function removeGuardian(address guardian) external;

    function setGuardianClassMintingFee(
        address guardian,
        uint256 classID,
        uint256 mintingFee
    ) external;

    function setGuardianClassRedemptionFee(
        address guardian,
        uint256 classID,
        uint256 redemptionFee
    ) external;

    function setGuardianClassGuardianFeeRate(
        address guardian,
        uint256 classID,
        uint256 guardianFeeRate
    ) external;

    function setGuardianClassGuardianFeePeriodAndRate(
        address guardian,
        uint256 classID,
        GuardianFeeRatePeriods guardianFeeRatePeriod,
        uint256 guardianFeeRate
    ) external;

    function setGuardianClassURI(
        address guardian,
        uint256 classID,
        string calldata uri
    ) external;

    function setGuardianClassActiveStatus(
        address guardian,
        uint256 classID,
        bool activeStatus
    ) external;

    function setGuardianClassMaximumCoverage(
        address guardian,
        uint256 classID,
        uint256 maximumCoverage
    ) external;

    function addGuardianClass(
        address guardian,
        uint256 maximumCoverage,
        uint256 mintingFee,
        uint256 redemptionFee,
        uint256 guardianFeeRate,
        GuardianFeeRatePeriods guardianFeeRatePeriod,
        string calldata uri
    ) external;

    function registerGuardian(
        address guardian,
        string calldata name,
        string calldata logo,
        string calldata policy,
        string calldata redirect,
        bytes32 physicalAddressHash,
        bool privacy
    ) external;

    function transferOwnership(address newOwner) external;

    function setVersion(bytes32 version_) external;

    function isAvailable(address guardian) external view returns (bool);

    function guardianInfo(
        address guardian
    )
        external
        view
        returns (
            bytes32,
            string memory,
            string memory,
            string memory,
            string memory,
            bool,
            bool
        );

    function guardianWhitelist(
        address guardian,
        address user
    ) external view returns (bool);

    function delegated(address guardian) external view returns (address);

    function getRedemptionFee(
        address guardian,
        uint256 classID
    ) external view returns (uint256);

    function getMintingFee(
        address guardian,
        uint256 classID
    ) external view returns (uint256);

    function isClassActive(
        address guardian,
        uint256 classID
    ) external view returns (bool);

    function minStorageTime() external view returns (uint256);

    function feesManager() external view returns (address);

    function stored(
        address guardian,
        IERC11554K collection,
        uint256 id
    ) external view returns (uint256);

    function whereItemStored(
        IERC11554K collection,
        uint256 id
    ) external view returns (address);

    function itemGuardianClass(
        IERC11554K collection,
        uint256 id
    ) external view returns (uint256);

    function guardianFeePaidUntil(
        address user,
        address collection,
        uint256 id
    ) external view returns (uint256);

    function isFeeAboveMinimum(
        uint256 guardianFeeAmount,
        uint256 numItems,
        address guardian,
        uint256 guardianClassIndex
    ) external view returns (bool);

    function getGuardianFeeRateByCollectionItem(
        IERC11554K collection,
        uint256 itemId
    ) external view returns (uint256);

    function getGuardianFeeRate(
        address guardian,
        uint256 guardianClassIndex
    ) external view returns (uint256);

    function isWhitelisted(address guardian) external view returns (bool);

    function inRepossession(
        address user,
        IERC11554K collection,
        uint256 id
    ) external view returns (uint256);

    function isDelegated(
        address guardian,
        address delegatee,
        IERC11554K collection
    ) external view returns (bool);
}

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

pragma solidity ^0.8.17;

/**
 * @dev GuardianTimeMath library. Provides support for converting between guardian fees and purchased storage time
 */
library GuardianTimeMath {
    /**
     * @dev Calculates the fee amount associated with the items
     * scaledByNumItems based on currGuardianFeePaidUntil guardianClassFeeRate
     * (scaled by the number being moved, for semi-fungibles).
     * @param currGuardianFeePaidUntil a timestamp that describes until when storage has been paid.
     * @param guardianClassFeeRate a guardian's guardian fee rate. Amount per second.
     * @param scaledByNumItems the number of items that are being stored by a guardian at the time of the query.
     * @return the remaining amount of guardian fee that is left within the `currGuardianFeePaidUntil` at the `guardianClassFeeRate` rate for `scaledByNumItems` items
     */
    function calculateRemainingFeeAmount(
        uint256 currGuardianFeePaidUntil,
        uint256 guardianClassFeeRate,
        uint256 guardianFeeRatePeriod,
        uint256 scaledByNumItems
    ) internal view returns (uint256) {
        if (currGuardianFeePaidUntil <= block.timestamp) {
            return 0;
        } else {
            return ((((currGuardianFeePaidUntil - block.timestamp) *
                guardianClassFeeRate) * scaledByNumItems) /
                guardianFeeRatePeriod);
        }
    }

    /**
     * @dev Calculates added guardian storage time based on
     * guardianFeePaid guardianClassFeeRate and numItems
     * (scaled by the number being moved, for semi-fungibles).
     * @param guardianFeePaid the amount of guardian fee that is being paid.
     * @param guardianClassFeeRate a guardian's guardian fee rate. Amount per time period.
     * @param guardianFeeRatePeriod the size of the period used in the guardian fee rate.
     * @param numItems the number of items that are being stored by a guardian at the time of the query.
     * @return the amount of guardian time that can be purchased from `guardianFeePaid` fee amount at the `guardianClassFeeRate` rate for `numItems` items
     */
    function calculateAddedGuardianTime(
        uint256 guardianFeePaid,
        uint256 guardianClassFeeRate,
        uint256 guardianFeeRatePeriod,
        uint256 numItems
    ) internal pure returns (uint256) {
        return
            (guardianFeePaid * guardianFeeRatePeriod) /
            (guardianClassFeeRate * numItems);
    }

    /**
     * @dev Function that allows us to transform an amount from the internal, 18 decimal format, to one that has another decimal precision.
     * @param internalAmount the amount in 18 decimal represenation.
     * @param toDecimals the amount of decimal precision we want the amount to have
     */
    function transformDecimalPrecision(
        uint256 internalAmount,
        uint256 toDecimals
    ) internal pure returns (uint256) {
        return (internalAmount / (10 ** (18 - toDecimals)));
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"BeneficiaryDoesNotOwnItem","type":"error"},{"inputs":[],"name":"CallerNotController","type":"error"},{"inputs":[],"name":"ClassNotActive","type":"error"},{"inputs":[],"name":"CollectionIsNotActiveOrLinked","type":"error"},{"inputs":[],"name":"DifferentPeriodRequired","type":"error"},{"inputs":[],"name":"FreeStorageItemsCantBeRepossessed","type":"error"},{"inputs":[],"name":"GuardianClassFeeRateTooLow","type":"error"},{"inputs":[],"name":"GuardianDoesNotStoreItem","type":"error"},{"inputs":[],"name":"GuardianFeeNotChangeableOnFreeStorageClass","type":"error"},{"inputs":[],"name":"GuardianFeePaidUntilStillInFuture","type":"error"},{"inputs":[],"name":"GuardianFeeRateLimitExceeded","type":"error"},{"inputs":[],"name":"GuardianFeeTooLow","type":"error"},{"inputs":[],"name":"GuardianFeeWindowHasntPassed","type":"error"},{"inputs":[],"name":"GuardianNotWhitelisted","type":"error"},{"inputs":[],"name":"ItemNotYetMinted","type":"error"},{"inputs":[],"name":"MinStorageTimeTooLow","type":"error"},{"inputs":[],"name":"MintingFeeTooLow","type":"error"},{"inputs":[],"name":"NewGuardianUnavailable","type":"error"},{"inputs":[],"name":"NoItemsToRepossess","type":"error"},{"inputs":[],"name":"NotCallersGuardianData","type":"error"},{"inputs":[],"name":"NotGuardianOfItems","type":"error"},{"inputs":[],"name":"OldGuardianAvailable","type":"error"},{"inputs":[],"name":"TooManyReposessionItems","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"components":[{"internalType":"bytes32","name":"addressHash","type":"bytes32"},{"internalType":"string","name":"logo","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"redirect","type":"string"},{"internalType":"string","name":"policy","type":"string"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isPrivate","type":"bool"}],"indexed":false,"internalType":"struct Guardians.GuardianInfo","name":"newGuardianInfo","type":"tuple"}],"name":"GuardianAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"classID","type":"uint256"},{"components":[{"internalType":"uint256","name":"maximumCoverage","type":"uint256"},{"internalType":"uint256","name":"mintingFee","type":"uint256"},{"internalType":"uint256","name":"redemptionFee","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRatePeriod","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRate","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRateMinimum","type":"uint256"},{"internalType":"uint256","name":"lastGuardianFeeRateIncrease","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"string","name":"uri","type":"string"}],"indexed":false,"internalType":"struct Guardians.GuardianClass","name":"newGuardianClass","type":"tuple"}],"name":"GuardianClassAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"classID","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"fieldIndexModified","type":"uint8"},{"components":[{"internalType":"uint256","name":"maximumCoverage","type":"uint256"},{"internalType":"uint256","name":"mintingFee","type":"uint256"},{"internalType":"uint256","name":"redemptionFee","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRatePeriod","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRate","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRateMinimum","type":"uint256"},{"internalType":"uint256","name":"lastGuardianFeeRateIncrease","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"string","name":"uri","type":"string"}],"indexed":false,"internalType":"struct Guardians.GuardianClass","name":"newGuardianClass","type":"tuple"}],"name":"GuardianClassModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint8","name":"fieldIndexModified","type":"uint8"},{"components":[{"internalType":"bytes32","name":"addressHash","type":"bytes32"},{"internalType":"string","name":"logo","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"redirect","type":"string"},{"internalType":"string","name":"policy","type":"string"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isPrivate","type":"bool"}],"indexed":false,"internalType":"struct Guardians.GuardianInfo","name":"newGuardianInfo","type":"tuple"}],"name":"GuardianModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"components":[{"internalType":"bytes32","name":"addressHash","type":"bytes32"},{"internalType":"string","name":"logo","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"redirect","type":"string"},{"internalType":"string","name":"policy","type":"string"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isPrivate","type":"bool"}],"indexed":false,"internalType":"struct Guardians.GuardianInfo","name":"newGuardianInfo","type":"tuple"}],"name":"GuardianRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"}],"name":"GuardianRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"fromGuardian","type":"address"},{"indexed":true,"internalType":"address","name":"toGuardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"toGuardianClassId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"contract IERC11554K","name":"collection","type":"address"}],"name":"ItemMoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"classID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"contract IERC11554K","name":"collection","type":"address"}],"name":"ItemStored","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":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"contract IERC11554K","name":"collection","type":"address"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SetForRepossession","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"guardian","type":"address"},{"indexed":false,"internalType":"uint256","name":"timeAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"},{"indexed":false,"internalType":"contract IERC11554K","name":"collection","type":"address"}],"name":"StorageTimeAdded","type":"event"},{"inputs":[],"name":"DAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"HOUR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINUTE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENTAGE_FACTOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SECOND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"addGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"maximumCoverage","type":"uint256"},{"internalType":"uint256","name":"mintingFee","type":"uint256"},{"internalType":"uint256","name":"redemptionFee","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRate","type":"uint256"},{"internalType":"enum Guardians.GuardianFeeRatePeriods","name":"guardianFeeRatePeriod","type":"uint8"},{"internalType":"string","name":"uri","type":"string"}],"name":"addGuardianClass","outputs":[{"internalType":"uint256","name":"classID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"uint256","name":"itemId","type":"uint256"},{"internalType":"uint256","name":"guardianFeeAmount","type":"uint256"}],"name":"addStorageTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC11554K[]","name":"collections","type":"address[]"},{"internalType":"address[]","name":"beneficiaries","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"guardianFeeAmounts","type":"uint256[]"}],"name":"batchAddStorageTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"address[]","name":"users","type":"address[]"},{"internalType":"bool","name":"whitelistStatus","type":"bool"}],"name":"changeWhitelistUsersStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IERC11554KController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"address","name":"mintAddress","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"guardianClassIndex","type":"uint256"},{"internalType":"uint256","name":"guardianFeeAmount","type":"uint256"},{"internalType":"uint256","name":"numItems","type":"uint256"},{"internalType":"address","name":"feePayer","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"paymentAsset","type":"address"}],"name":"controllerStoreItem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"numItems","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"controllerTakeItemOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldGuardian","type":"address"},{"internalType":"address","name":"newGuardian","type":"address"}],"name":"copyGuardianClasses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"contract IERC11554K","name":"collection","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegated","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"delegatedAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract IERC11554K","name":"","type":"address"}],"name":"delegatedCollection","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feesManager","outputs":[{"internalType":"contract IFeesManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"}],"name":"getGuardianFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"uint256","name":"itemId","type":"uint256"}],"name":"getGuardianFeeRateByCollectionItem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"}],"name":"getGuardianFeeRatePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"uint256","name":"itemId","type":"uint256"}],"name":"getGuardianFeeRatePeriodByCollectionItem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"}],"name":"getMintingFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"}],"name":"getRedemptionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"globalItemGuardianFeePaidUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"guardianClassesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract IERC11554K","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"guardianFeePaidUntil","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardianFeeSetWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"guardianInfo","outputs":[{"internalType":"bytes32","name":"addressHash","type":"bytes32"},{"internalType":"string","name":"logo","type":"string"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"redirect","type":"string"},{"internalType":"string","name":"policy","type":"string"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"bool","name":"isPrivate","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"guardianWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"guardiansClasses","outputs":[{"internalType":"uint256","name":"maximumCoverage","type":"uint256"},{"internalType":"uint256","name":"mintingFee","type":"uint256"},{"internalType":"uint256","name":"redemptionFee","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRatePeriod","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRate","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRateMinimum","type":"uint256"},{"internalType":"uint256","name":"lastGuardianFeeRateIncrease","type":"uint256"},{"internalType":"bool","name":"isActive","type":"bool"},{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract IERC11554K","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"inRepossession","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"minimumRequestFee_","type":"uint256"},{"internalType":"uint256","name":"guardianFeeSetWindow_","type":"uint256"},{"internalType":"uint256","name":"maximumGuardianFeeSet_","type":"uint256"},{"internalType":"contract IFeesManager","name":"feesManager_","type":"address"},{"internalType":"contract IERC11554KController","name":"controller_","type":"address"},{"internalType":"bytes32","name":"version_","type":"bytes32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"isAvailable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"}],"name":"isClassActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"contract IERC11554K","name":"collection","type":"address"}],"name":"isDelegated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"guardianFeeAmount","type":"uint256"},{"internalType":"uint256","name":"numItems","type":"uint256"},{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"guardianClassIndex","type":"uint256"}],"name":"isFeeAboveMinimum","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"itemGuardianClass","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maximumGuardianFeeSet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minStorageTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minimumRequestFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"address","name":"oldGuardian","type":"address"},{"internalType":"address","name":"newGuardian","type":"address"},{"internalType":"uint256[]","name":"newGuardianClassIndeces","type":"uint256[]"}],"name":"moveItems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"logo","type":"string"},{"internalType":"string","name":"policy","type":"string"},{"internalType":"string","name":"redirect","type":"string"},{"internalType":"bytes32","name":"physicalAddressHash","type":"bytes32"},{"internalType":"bool","name":"privacy","type":"bool"}],"name":"registerGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"}],"name":"removeGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"bool","name":"activity","type":"bool"}],"name":"setActivity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC11554KController","name":"controller_","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IFeesManager","name":"feesManager_","type":"address"}],"name":"setFeesManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"bool","name":"activeStatus","type":"bool"}],"name":"setGuardianClassActiveStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"enum Guardians.GuardianFeeRatePeriods","name":"guardianFeeRatePeriod","type":"uint8"},{"internalType":"uint256","name":"guardianFeeRate","type":"uint256"}],"name":"setGuardianClassGuardianFeePeriodAndRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"uint256","name":"guardianFeeRate","type":"uint256"}],"name":"setGuardianClassGuardianFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"uint256","name":"maximumCoverage","type":"uint256"}],"name":"setGuardianClassMaximumCoverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"uint256","name":"mintingFee","type":"uint256"}],"name":"setGuardianClassMintingFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"uint256","name":"redemptionFee","type":"uint256"}],"name":"setGuardianClassRedemptionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"uint256","name":"classID","type":"uint256"},{"internalType":"string","name":"uri","type":"string"}],"name":"setGuardianClassURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"guardianFeeSetWindow_","type":"uint256"}],"name":"setGuardianFeeSetWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"collection","type":"address"},{"internalType":"uint256","name":"itemId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"setItemsToRepossessed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"string","name":"logo","type":"string"}],"name":"setLogo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maximumGuardianFeeSet_","type":"uint256"}],"name":"setMaximumGuardianFeeSet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minStorageTime_","type":"uint256"}],"name":"setMinStorageTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minimumRequestFee_","type":"uint256"}],"name":"setMinimumRequestFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"string","name":"name","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"bytes32","name":"physicalAddressHash","type":"bytes32"}],"name":"setPhysicalAddressHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"string","name":"policy","type":"string"}],"name":"setPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"bool","name":"privacy","type":"bool"}],"name":"setPrivacy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"guardian","type":"address"},{"internalType":"string","name":"redirect","type":"string"}],"name":"setRedirect","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"version_","type":"bytes32"}],"name":"setVersion","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"shiftGuardianFeesOnTokenMove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"contract IERC11554K","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stored","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":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"contract IERC11554K","name":"collection","type":"address"}],"name":"undelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC11554K","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"whereItemStored","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b506159bf80620000216000396000f3fe608060405234801561001057600080fd5b50600436106104535760003560e01c8063715018a611610241578063bc302c881161013b578063ec9cd925116100c3578063fbdfc81511610087578063fbdfc81514610a92578063fc113aa514610aa5578063fca6bab014610ab8578063fdd264fb14610acb578063fe8020ba14610aff57600080fd5b8063ec9cd92514610a27578063ee01e5e714610a3a578063f2fde38b14610a43578063f3598ad914610a56578063f77c479114610a7f57600080fd5b8063ca5f81b51161010a578063ca5f81b5146109b4578063cd6740e5146109c7578063d78a3845146109f8578063de14e54d14610a01578063e63f366414610a1457600080fd5b8063bc302c8814610968578063bd2127841461097b578063bdb343721461098e578063be1f7828146109a157600080fd5b80638f5c81a1116101c9578063a526d83b1161018d578063a526d83b146108d8578063a54bc0b2146108eb578063abcac6bc146108fe578063b4a90fc71461092f578063b54d01da1461096057600080fd5b80638f5c81a11461086e578063923313771461088157806392eefe9b146108aa5780639da254ad146108bd578063a39dc9be146108d057600080fd5b806385cc313c1161021057806385cc313c146107f657806389d29297146108095780638ab656861461081c5780638d57c2031461082f5780638da5cb5b1461085d57600080fd5b8063715018a6146107c957806372539511146107d15780637c25509d146107e4578063800375a7146107ed57600080fd5b806335fa4384116103525780634cf31905116102da5780635e31b0731161029e5780635e31b07314610749578063667d3fb41461075c5780636cf667d41461076f5780636e2a42651461078257806371404156146107b657600080fd5b80634cf31905146106f4578063512f87781461070757806354fd4d501461071a5780635879fa92146107235780635b8afb701461073657600080fd5b806344ab1ee81161032157806344ab1ee814610662578063462b972514610675578063479f43651461068857806348d378561461069b578063497adbcb146106c657600080fd5b806335fa4384146105f1578063399ef453146106045780633af32abf1461062c5780634390c4ee1461064f57600080fd5b80631c89382a116103e05780632896f60b116103a45780632896f60b1461059257806328b047c8146105a557806328edec8e146105b85780633121db1c146105cb57806334a07d10146105de57600080fd5b80631c89382a1461053e5780631d21d4d9146105515780631ee9211f146105645780632750738f1461057757806327cfe8561461058a57600080fd5b806314f2101f1161042757806314f2101f146104da578063183e1a24146104fd578063197a2a7714610510578063198a8f65146105235780631ab3995a1461052b57600080fd5b80621f8a8b1461045857806305a9e0731461046d578063092d79c21461049d57806310bfbaea146104c3575b600080fd5b61046b610466366004614a40565b610b2a565b005b606554610480906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6104b06104ab366004614a79565b610c15565b6040516104949796959493929190614ae3565b6104cc606a5481565b604051908152602001610494565b6104ed6104e8366004614b52565b610e76565b6040519015158152602001610494565b6104cc61050b366004614b9d565b610edd565b6104ed61051e366004614bc9565b610fd9565b6104cc603c81565b61046b610539366004614b9d565b611033565b61046b61054c366004614a79565b6110fb565b61046b61055f366004614c08565b611125565b6104cc610572366004614b9d565b61128c565b61046b610585366004614c66565b6112d0565b6104cc6112fe565b6104ed6105a0366004614a79565b611317565b61046b6105b3366004614cc8565b61135c565b61046b6105c6366004614d1d565b61145a565b61046b6105d9366004614cc8565b611596565b61046b6105ec366004614d54565b611685565b61046b6105ff366004614d89565b611793565b610617610612366004614b9d565b611864565b60405161049499989796959493929190614db7565b6104ed61063a366004614a79565b606b6020526000908152604090205460ff1681565b61046b61065d366004614e53565b611964565b61046b610670366004614d54565b611a5a565b6104cc610683366004614b9d565b611b7d565b61046b610696366004614d54565b611bc1565b6104cc6106a9366004614b9d565b607260209081526000928352604080842090915290825290205481565b6104ed6106d4366004614d89565b606d60209081526000928352604080842090915290825290205460ff1681565b61046b610702366004614c66565b611caa565b61046b610715366004614eff565b611cb7565b6104cc60785481565b61046b610731366004614cc8565b612131565b61046b610744366004614c66565b612220565b61046b610757366004614f45565b61222d565b6104cc61076a366004614b9d565b612340565b61046b61077d366004614fad565b61243b565b610480610790366004614d89565b60776020908152600092835260408084209091529082529020546001600160a01b031681565b61046b6107c4366004614a79565b612584565b61046b6125ed565b6104cc6107df366004614b9d565b612601565b6104cc60685481565b6104cc60695481565b61046b610804366004614d54565b61262b565b61046b610817366004614eff565b612771565b61046b61082a366004614d89565b612afe565b6104ed61083d366004614d89565b607660209081526000928352604080842090915290825290205460ff1681565b6033546001600160a01b0316610480565b61046b61087c366004615009565b612b53565b6104cc61088f366004614a79565b6001600160a01b03166000908152606f602052604090205490565b61046b6108b8366004614a79565b612d22565b61046b6108cb366004615040565b612d4c565b6104cc612e8c565b61046b6108e6366004614a79565b612e97565b61046b6108f9366004614d89565b612f18565b6104cc61090c366004615133565b607360209081526000938452604080852082529284528284209052825290205481565b6104cc61093d366004615133565b607060209081526000938452604080852082529284528284209052825290205481565b6104cc600181565b61046b610976366004615174565b612f61565b6104cc61098936600461521b565b613395565b61046b61099c366004614c66565b613443565b6104cc6109af366004614b9d565b613450565b61046b6109c2366004614c66565b61347a565b6104cc6109d5366004615133565b607560209081526000938452604080852082529284528284209052825290205481565b6104cc60675481565b61046b610a0f366004614a40565b613487565b6104ed610a22366004614b9d565b61355e565b61046b610a35366004614cc8565b6135a6565b6104cc61271081565b61046b610a51366004614a79565b613695565b610480610a64366004614a79565b606e602052600090815260409020546001600160a01b031681565b606654610480906001600160a01b031681565b61046b610aa03660046152a8565b61370e565b61046b610ab33660046152de565b613968565b61046b610ac636600461538e565b613a0d565b610480610ad9366004614b9d565b60716020908152600092835260408084209091529082529020546001600160a01b031681565b6104cc610b0d366004614b9d565b607460209081526000928352604080842090915290825290205481565b6001600160a01b0382166000908152606b6020526040902054829060ff16610b65576040516371d42f3560e11b815260040160405180910390fd5b82610b786033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610bb957336001600160a01b03821614610bb9576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0384166000818152606c60205260409081902060058101805461ff00191661010088151502179055905160008051602061594a83398151915291610c079160049190615532565b60405180910390a250505050565b606c6020526000908152604090208054600182018054919291610c37906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610c63906153ed565b8015610cb05780601f10610c8557610100808354040283529160200191610cb0565b820191906000526020600020905b815481529060010190602001808311610c9357829003601f168201915b505050505090806002018054610cc5906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf1906153ed565b8015610d3e5780601f10610d1357610100808354040283529160200191610d3e565b820191906000526020600020905b815481529060010190602001808311610d2157829003601f168201915b505050505090806003018054610d53906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610d7f906153ed565b8015610dcc5780601f10610da157610100808354040283529160200191610dcc565b820191906000526020600020905b815481529060010190602001808311610daf57829003601f168201915b505050505090806004018054610de1906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0d906153ed565b8015610e5a5780601f10610e2f57610100808354040283529160200191610e5a565b820191906000526020600020905b815481529060010190602001808311610e3d57829003601f168201915b5050506005909301549192505060ff8082169161010090041687565b6001600160a01b0383811660009081526077602090815260408083208585168452909152812054909184811691161480610ed557506001600160a01b0380851660009081526076602090815260408083209387168352929052205460ff165b949350505050565b60405163bd85b03960e01b8152600481018290526000906001600160a01b0384169063bd85b03990602401602060405180830381865afa158015610f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f49919061554e565b600003610f6957604051633b41868f60e21b815260040160405180910390fd5b6001600160a01b0380841660008181526071602090815260408083208784528252808320549094168252606f8152838220928252607281528382208683529052919091205481548110610fbe57610fbe615567565b90600052602060002090600902016004015490505b92915050565b600080610fe68484612601565b90506000610ff48585613450565b905081600003611017576040516333adb20360e11b815260040160405180910390fd5b61102387838389613bbb565b606a541115979650505050505050565b6001600160a01b0382166000908152606b6020526040902054829060ff1661106e576040516371d42f3560e11b815260040160405180910390fd5b826110816033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146110c257336001600160a01b038216146110c2576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0384166000818152606c6020526040808220868155905160008051602061594a83398151915292610c07929091615532565b611103613be4565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16158080156111455750600054600160ff909116105b8061115f5750303b15801561115f575060005460ff166001145b6111c75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156111ea576000805461ff0019166101001790555b6111f2613c3e565b6067879055606886905560698590556276a700606a55606580546001600160a01b038087166001600160a01b031992831617909255606680549286169290911691909117905560788290558015611283576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6001600160a01b0382166000908152606f602052604081208054839081106112b6576112b6615567565b906000526020600020906009020160020154905092915050565b6112d8613be4565b806000036112f957604051637beed6ff60e11b815260040160405180910390fd5b606a55565b611309603c80615593565b611314906018615593565b81565b6001600160a01b0381166000908152606b602052604081205460ff168015610fd35750506001600160a01b03166000908152606c602052604090206005015460ff1690565b6001600160a01b0383166000908152606b6020526040902054839060ff16611397576040516371d42f3560e11b815260040160405180910390fd5b836113aa6033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146113eb57336001600160a01b038216146113eb576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c6020526040902060010161141184868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160019190615532565b60405180910390a25050505050565b6001600160a01b0383166000908152606b6020526040902054839060ff16611495576040516371d42f3560e11b815260040160405180910390fd5b836114a86033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146114e957336001600160a01b038216146114e9576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f6020526040902080548491908690811061151657611516615567565b6000918252602080832060076009909302018201805494151560ff19909516949094179093556001600160a01b038816808352606f9093526040909120805460008051602061596a83398151915292889290918390811061157957611579615567565b906000526020600020906009020160405161144b9392919061573f565b6001600160a01b0383166000908152606b6020526040902054839060ff166115d1576040516371d42f3560e11b815260040160405180910390fd5b836115e46033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461162557336001600160a01b03821614611625576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c6020526040902060020161164b84868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160029190615532565b6001600160a01b0383166000908152606b6020526040902054839060ff166116c0576040516371d42f3560e11b815260040160405180910390fd5b836116d36033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461171457336001600160a01b03821614611714576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f6020526040902080548491908690811061174157611741615567565b600091825260208083206009909202909101929092556001600160a01b038716808252606f90925260408120805460008051602061596a83398151915292889290918390811061157957611579615567565b336000818152606b602052604090205460ff166117c3576040516371d42f3560e11b815260040160405180910390fd5b6001600160a01b038216611817576000607681335b6001600160a01b03908116825260208083019390935260409182016000908120918816815292529020805491151560ff19909216919091179055505050565b6000607781335b6001600160a01b039081168252602080830193909352604091820160009081208783168252909352912080546001600160a01b031916929091169190911790555b505050565b606f602052816000526040600020818154811061188057600080fd5b9060005260206000209060090201600091509150508060000154908060010154908060020154908060030154908060040154908060050154908060060154908060070160009054906101000a900460ff16908060080180546118e1906153ed565b80601f016020809104026020016040519081016040528092919081815260200182805461190d906153ed565b801561195a5780601f1061192f5761010080835404028352916020019161195a565b820191906000526020600020905b81548152906001019060200180831161193d57829003601f168201915b5050505050905089565b61196c613be4565b61197584611317565b1561199357604051634c620c3f60e11b815260040160405180910390fd5b61199c83611317565b6119b95760405163cedb19a160e01b815260040160405180910390fd5b60005b85811015611a50576119e6848484848181106119da576119da615567565b9050602002013561355e565b611a03576040516339cf183d60e11b815260040160405180910390fd5b611a4088888884818110611a1957611a19615567565b905060200201358787878787818110611a3457611a34615567565b90506020020135613c6d565b611a4981615761565b90506119bc565b5050505050505050565b6001600160a01b0383166000908152606b6020526040902054839060ff16611a95576040516371d42f3560e11b815260040160405180910390fd5b83611aa86033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614611ae957336001600160a01b03821614611ae9576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f60205260409020805484919086908110611b1657611b16615567565b906000526020600020906009020160020181905550846001600160a01b031660008051602061596a833981519152856002606f60008a6001600160a01b03166001600160a01b03168152602001908152602001600020888154811061157957611579615567565b6001600160a01b0382166000908152606f60205260408120805483908110611ba757611ba7615567565b906000526020600020906009020160010154905092915050565b6001600160a01b0383166000908152606b6020526040902054839060ff16611bfc576040516371d42f3560e11b815260040160405180910390fd5b83611c0f6033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614611c5057336001600160a01b03821614611c50576040516305fa117f60e11b815260040160405180910390fd5b611ca3858585606f60008a6001600160a01b03166001600160a01b031681526020019081526020016000208881548110611c8c57611c8c615567565b906000526020600020906009020160030154613d6c565b5050505050565b611cb2613be4565b606955565b6066546001600160a01b031663aee3d144336040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015611d0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d33919061577a565b1580611db857506066546001600160a01b031663236d64a3336040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015611d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db6919061577a565b155b15611dd657604051632ed58dfb60e21b815260040160405180910390fd5b336000611de38285610edd565b90506000611df18386612340565b6001600160a01b038089166000908152607360209081526040808320938816835292815282822089835290529081205491925090611e31908484886140e6565b6001600160a01b03808a166000818152607360209081526040808320948a168084529482528083208c8452909152808220549051627eeac760e11b81526004810193909352602483018b905293945092611eda9290918791879162fdd58e906044015b602060405180830381865afa158015611eb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed5919061554e565b6140e6565b6001600160a01b03808a166000818152607360209081526040808320948b168084529482528083208d8452909152808220549051627eeac760e11b81526004810193909352602483018c905293945092611f419290918891889162fdd58e90604401611e94565b604051627eeac760e11b81526001600160a01b038c81166004830152602482018b905291925060009189919089169062fdd58e90604401602060405180830381865afa158015611f95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb9919061554e565b611fc39190615797565b905080600003612002576001600160a01b03808c166000908152607360209081526040808320938b1683529281528282208c8352905290812055612050565b61201761200f8585615797565b878784613bbb565b61202190426157aa565b6001600160a01b03808d166000908152607360209081526040808320938c1683529281528282208d8352905220555b604051627eeac760e11b81526001600160a01b038b81166004830152602482018b90526000918a918a169062fdd58e90604401602060405180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c4919061554e565b6120ce91906157aa565b90506120e56120dd86856157aa565b888884613bbb565b6120ef90426157aa565b6001600160a01b039b8c1660009081526073602090815260408083209b909e168252998a528c81209b81529a9098525050509690952092909255505050505050565b6001600160a01b0383166000908152606b6020526040902054839060ff1661216c576040516371d42f3560e11b815260040160405180910390fd5b8361217f6033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146121c057336001600160a01b038216146121c0576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c602052604090206003016121e684868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160039190615532565b612228613be4565b606755565b6001600160a01b0384166000908152606b6020526040902054849060ff16612268576040516371d42f3560e11b815260040160405180910390fd5b8461227b6033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146122bc57336001600160a01b038216146122bc576040516305fa117f60e11b815260040160405180910390fd5b60005b84811015611283576001600160a01b0387166000908152606d6020526040812085918888858181106122f3576122f3615567565b90506020020160208101906123089190614a79565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905561233981615761565b90506122bf565b60405163bd85b03960e01b8152600481018290526000906001600160a01b0384169063bd85b03990602401602060405180830381865afa158015612388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ac919061554e565b6000036123cc57604051633b41868f60e21b815260040160405180910390fd5b6001600160a01b0380841660008181526071602090815260408083208784528252808320549094168252606f815283822092825260728152838220868352905291909120548154811061242157612421615567565b906000526020600020906009020160030154905092915050565b6001600160a01b0384166000908152606b6020526040902054849060ff16612476576040516371d42f3560e11b815260040160405180910390fd5b846124896033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146124ca57336001600160a01b038216146124ca576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0386166000908152606f60205260409020805485918591889081106124f8576124f8615567565b9060005260206000209060090201600801918261251692919061560e565b506001600160a01b0386166000818152606f60205260409020805460008051602061596a833981519152918891600891908390811061255757612557615567565b90600052602060002090600902016040516125749392919061573f565b60405180910390a2505050505050565b61258c613be4565b6001600160a01b0381166000818152606b60209081526040808320805460ff19908116909155606c9092528083206005018054909216909155517fb8107d0c6b40be480ce3172ee66ba6d64b71f6b1685a851340036e6e2e3e3c529190a250565b6125f5613be4565b6125ff6000614129565b565b6001600160a01b0382166000908152606f60205260408120805483908110610fbe57610fbe615567565b6001600160a01b0383166000908152606b6020526040902054839060ff16612666576040516371d42f3560e11b815260040160405180910390fd5b836126796033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146126ba57336001600160a01b038216146126ba576040516305fa117f60e11b815260040160405180910390fd5b6067548310156126dd5760405163522036bf60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f6020526040902080548491908690811061270a5761270a615567565b906000526020600020906009020160010181905550846001600160a01b031660008051602061596a833981519152856001606f60008a6001600160a01b03166001600160a01b03168152602001908152602001600020888154811061157957611579615567565b604051627eeac760e11b81526001600160a01b038481166004830152602482018490526000919086169062fdd58e90604401602060405180830381865afa1580156127c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e4919061554e565b6001600160a01b038087166000818152607160209081526040808320898452825280832054938352607282528083208984529091528120549394509116919061282d8383612601565b905080600003612850576040516333adb20360e11b815260040160405180910390fd5b84600003612871576040516306c95d7d60e41b815260040160405180910390fd5b83600003612892576040516369bdf96560e11b815260040160405180910390fd5b6001600160a01b0383166128b95760405163137849f160e11b815260040160405180910390fd5b60006128d086836128ca8787613450565b88613bbb565b6001600160a01b03808a166000908152607360209081526040808320938e1683529281528282208b83529052908120805492935083929091906129149084906157aa565b9091555050604080518281526001600160a01b038a811660208301528b81168284015291519186169189917f29de542d58d5280b82118289d7236d2b096f3e56797fd3bc4228f19a3c476947919081900360600190a3506065546001600160a01b031663348709b4866129878686613450565b6129918886615593565b61299b91906157bd565b86607360008d6001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008c8152602001908152602001600020546129fd3390565b606660009054906101000a90046001600160a01b03166001600160a01b0316633013ce296040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7691906157df565b6040516001600160e01b031960e089901b168152600481019690965260248601949094526001600160a01b0392831660448601526064850191909152811660848401521660a482015260c401600060405180830381600087803b158015612adc57600080fd5b505af1158015612af0573d6000803e3d6000fd5b505050505050505050505050565b336000818152606b602052604090205460ff16612b2e576040516371d42f3560e11b815260040160405180910390fd5b6001600160a01b038216612b4857600160766000336117d8565b82607760003361181e565b6001600160a01b038381166000908152607160209081526040808320868452909152902054163314612b985760405163bc1a99ad60e01b815260040160405180910390fd5b612ba28383610edd565b600003612bc25760405163da9335d560e01b815260040160405180910390fd5b6001600160a01b0380821660009081526073602090815260408083209387168352928152828220858352905220544211612c0f576040516341f6b9a560e01b815260040160405180910390fd5b604051627eeac760e11b81526001600160a01b038281166004830152602482018490526000919085169062fdd58e90604401602060405180830381865afa158015612c5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c82919061554e565b905080600003612ca5576040516305319efb60e41b815260040160405180910390fd5b6001600160a01b0382811660009081526075602090815260408083209388168084529382528083208784529091529020805490839055903390857feef808aafa779451f3107a5033b5d50922fbd85286781c04ba9a3a88b7f27d77612d0a8587615797565b60405190815260200160405180910390a45050505050565b612d2a613be4565b606680546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038b166000908152606c6020526040902060058101805460ff19166001179055600201612d818a8c8361560e565b506001600160a01b038b166000908152606c60205260409020600101612da8888a8361560e565b506001600160a01b038b166000908152606c60205260409020600401612dcf86888361560e565b506001600160a01b038b166000908152606c6020526040902060058101805461ff00191661010084151502179055600301612e0b84868361560e565b506001600160a01b038b166000908152606c60205260409020829055612e308b612e97565b6001600160a01b038b166000818152606c60205260409081902090517f40a85abf2e067de420759997226b243a11146e32797c459e0ae521c164b3ef7c91612e77916157fc565b60405180910390a25050505050505050505050565b611314603c80615593565b612e9f613be4565b6001600160a01b0381166000818152606b602090815260408083208054600160ff199182168117909255606c90935292819020600581018054909316909317909155517fa08c78c5ffa2e84c547405de8308d3981bfc147bbe8186049de946adf23bedf291612f0d916157fc565b60405180910390a250565b612f20613be4565b60005b6001600160a01b0383166000908152606f602052604090205481101561185f57612f4e83838361417b565b5080612f5981615761565b915050612f23565b6066546001600160a01b0316336001600160a01b031614612f9557604051632d5fb10f60e01b815260040160405180910390fd5b6001600160a01b038087166000908152607060209081526040808320938d1683529281528282208a835290529081208054859290612fd49084906157aa565b90915550506001600160a01b0389811660008181526071602090815260408083208c8452825280832080546001600160a01b031916958c169586179055928252607281528282208b83528152828220899055928152606f909252812080548790811061304257613042615567565b906000526020600020906009020160040154111561338a576001600160a01b038089166000908152607360209081526040808320938d1683529281528282208a835290529081205490036130c1576001600160a01b038089166000908152607360209081526040808320938d1683529281528282208a83529052204290555b6001600160a01b0386166000908152606f602052604081208054613151918791899081106130f1576130f1615567565b906000526020600020906009020160040154606f60008b6001600160a01b03166001600160a01b03168152602001908152602001600020898154811061313957613139615567565b90600052602060002090600902016003015487613bbb565b6001600160a01b03808b166000908152607360209081526040808320938f1683529281528282208c83529052908120805492935083929091906131959084906157aa565b9091555050604080518281526001600160a01b038b811660208301528c8116828401529151918916918a917f29de542d58d5280b82118289d7236d2b096f3e56797fd3bc4228f19a3c476947919081900360600190a3506065546001600160a01b031663348709b4856132088989613450565b6001600160a01b038a166000908152606f6020526040902080548891908b90811061323557613235615567565b9060005260206000209060090201600401546132519190615593565b61325b91906157bd565b89607360008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008f6001600160a01b03166001600160a01b0316815260200190815260200160002060008d81526020019081526020016000205487876040518763ffffffff1660e01b815260040161330a9695949392919095865260208601949094526001600160a01b0392831660408601526060850191909152811660808401521660a082015260c00190565b600060405180830381600087803b15801561332457600080fd5b505af1158015613338573d6000803e3d6000fd5b505060408051888152602081018b90526001600160a01b038d8116828401529151918a1693507f9137dbe71594712b8c41002a261f3818dd6e951587d83c552606f4c53100f62b925081900360600190a25b505050505050505050565b6001600160a01b0388166000908152606b6020526040812054899060ff166133d0576040516371d42f3560e11b815260040160405180910390fd5b896133e36033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461342457336001600160a01b03821614613424576040516305fa117f60e11b815260040160405180910390fd5b6134348b8b8b8b8b8b8b8b6145cc565b9b9a5050505050505050505050565b61344b613be4565b606855565b6001600160a01b0382166000908152606f6020526040812080548390811061242157612421615567565b613482613be4565b607855565b6001600160a01b0382166000908152606b6020526040902054829060ff166134c2576040516371d42f3560e11b815260040160405180910390fd5b826134d56033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461351657336001600160a01b03821614613516576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0384166000818152606c6020526040908190206005808201805460ff1916881515179055915160008051602061594a83398151915292610c07929091615532565b6001600160a01b0382166000908152606f6020526040812080548390811061358857613588615567565b600091825260209091206009909102016007015460ff169392505050565b6001600160a01b0383166000908152606b6020526040902054839060ff166135e1576040516371d42f3560e11b815260040160405180910390fd5b836135f46033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461363557336001600160a01b03821614613635576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c6020526040902060040161365b84868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160049190615532565b61369d613be4565b6001600160a01b0381166137025760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016111be565b61370b81614129565b50565b6001600160a01b0384166000908152606b6020526040902054849060ff16613749576040516371d42f3560e11b815260040160405180910390fd5b8461375c6033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461379d57336001600160a01b0382161461379d576040516305fa117f60e11b815260040160405180910390fd5b6000808560038111156137b2576137b261580f565b036137bf5750600161383d565b60018560038111156137d3576137d361580f565b036137e05750603c61383d565b60028560038111156137f4576137f461580f565b0361380b57613804603c80615593565b905061383d565b600385600381111561381f5761381f61580f565b0361383d5761382f603c80615593565b61383a906018615593565b90505b6001600160a01b0387166000908152606f6020526040902080548291908890811061386a5761386a615567565b9060005260206000209060090201600301540361389a5760405163842cebc360e01b815260040160405180910390fd5b6138a687878684613d6c565b6001600160a01b0387166000908152606f602052604090208054829190889081106138d3576138d3615567565b906000526020600020906009020160030181905550866001600160a01b031660008051602061596a833981519152876003606f60008c6001600160a01b03166001600160a01b031681526020019081526020016000208a8154811061393a5761393a615567565b90600052602060002090600902016040516139579392919061573f565b60405180910390a250505050505050565b60005b8381101561338a576139fb89898381811061398857613988615567565b905060200201602081019061399d9190614a79565b8888848181106139af576139af615567565b90506020020160208101906139c49190614a79565b8787858181106139d6576139d6615567565b905060200201358686868181106139ef576139ef615567565b90506020020135612771565b80613a0581615761565b91505061396b565b6066546001600160a01b0316336001600160a01b031614613a4157604051632d5fb10f60e01b815260040160405180910390fd5b6001600160a01b0380821660009081526075602090815260408083209388168352928152828220868352905220548211613a8e5760405163481ae58160e01b815260040160405180910390fd5b6001600160a01b0384166000908152607260209081526040808320868452909152812054613abd908790612601565b6001600160a01b038616600090815260726020908152604080832088845290915281205491925090613af0908890613450565b90508115613b0857613b0683878787868661482d565b505b6001600160a01b038088166000908152607060209081526040808320938a16835292815282822088835290529081208054869290613b47908490615797565b90915550506001600160a01b038088166000908152607060209081526040808320938a168352928152828220888352905290812054900361128357505050506001600160a01b039190911660009081526071602090815260408083209383529290522080546001600160a01b031916905550565b6000613bc78285615593565b613bd18487615593565b613bdb91906157bd565b95945050505050565b6033546001600160a01b031633146125ff5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016111be565b600054610100900460ff16613c655760405162461bcd60e51b81526004016111be90615825565b6125ff6149d2565b6001600160a01b0380841660009081526070602081815260408084208a86168086529083528185208a865283528185208054908690559588168552928252808420928452918152818320888452905281208054839290613cce9084906157aa565b90915550506001600160a01b0386811660008181526071602090815260408083208a8452825280832080546001600160a01b031916898716908117909155848452607283528184208b855283529281902087905580518781529182018a9052810192909252918616907fa6beab620e184a03527e5ae53cfcf2bcc0a561f7fe957d28839a116e45ef70379060600160405180910390a3505050505050565b81600003613d8d576040516333adb20360e11b815260040160405180910390fd5b6001600160a01b0384166000908152606f60205260409020805484908110613db757613db7615567565b906000526020600020906009020160040154600003613de95760405163031fbaf760e41b815260040160405180910390fd5b6001600160a01b0384166000908152606f60205260408120805485908110613e1357613e13615567565b906000526020600020906009020160030154905080606f6000876001600160a01b03166001600160a01b031681526020019081526020016000208581548110613e5e57613e5e615567565b906000526020600020906009020160040154613e7a91906157bd565b613e8483856157bd565b1115613fbe576068546001600160a01b0386166000908152606f60205260409020805486908110613eb757613eb7615567565b906000526020600020906009020160060154613ed391906157aa565b421015613ef3576040516304caab9960e31b815260040160405180910390fd5b613eff61271082615593565b6069546001600160a01b0387166000908152606f60205260409020805487908110613f2c57613f2c615567565b906000526020600020906009020160040154613f489190615593565b613f5291906157bd565b613f5c83856157bd565b1115613f7b5760405163eb10300160e01b815260040160405180910390fd5b6001600160a01b0385166000908152606f60205260409020805442919086908110613fa857613fa8615567565b9060005260206000209060090201600601819055505b6001600160a01b0385166000908152606f60205260409020805484919086908110613feb57613feb615567565b90600052602060002090600902016004018190555080606f6000876001600160a01b03166001600160a01b03168152602001908152602001600020858154811061403757614037615567565b90600052602060002090600902016005015461405391906157bd565b61405d83856157bd565b10156140a6576001600160a01b0385166000908152606f6020526040902080548491908690811061409057614090615567565b9060005260206000209060090201600501819055505b6001600160a01b0385166000818152606f60205260409020805460008051602061596a833981519152918791600491908390811061157957611579615567565b60004285116140f757506000610ed5565b8282856141044289615797565b61410e9190615593565b6141189190615593565b61412291906157bd565b9050610ed5565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038083166000908152606f602052604080822080548251610120810184529488168452919092208054919391829190869081106141c1576141c1615567565b9060005260206000209060090201600001548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061420e5761420e615567565b9060005260206000209060090201600101548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061425b5761425b615567565b9060005260206000209060090201600201548152602001606f6000886001600160a01b03166001600160a01b0316815260200190815260200160002085815481106142a8576142a8615567565b9060005260206000209060090201600301548152602001606f6000886001600160a01b03166001600160a01b0316815260200190815260200160002085815481106142f5576142f5615567565b9060005260206000209060090201600401548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061434257614342615567565b9060005260206000209060090201600501548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061438f5761438f615567565b9060005260206000209060090201600601548152602001606f6000886001600160a01b03166001600160a01b0316815260200190815260200160002085815481106143dc576143dc615567565b600091825260208083206007600990930201919091015460ff16151583526001600160a01b0389168252606f81526040909120805492909101918690811061442657614426615567565b90600052602060002090600902016008018054614442906153ed565b80601f016020809104026020016040519081016040528092919081815260200182805461446e906153ed565b80156144bb5780601f10614490576101008083540402835291602001916144bb565b820191906000526020600020905b81548152906001019060200180831161449e57829003601f168201915b50505091909252505081546001808201845560009384526020938490208351600990930201918255928201519281019290925560408101516002830155606081015160038301556080810151600483015560a0810151600583015560c0810151600683015560e081015160078301805460ff191691151591909117905561010081015190919060088201906145509082615870565b5050506001600160a01b0383166000818152606f6020526040902080547f1d50952dd79441da39cded51d73c41faef52bb4929b6f9d51cc0e004842630e2918491829081106145a1576145a1615567565b90600052602060002090600902016040516145bd929190615930565b60405180910390a29392505050565b6001600160a01b0388166000908152606f602052604081205490808560038111156145f9576145f961580f565b0361460657506001614684565b600185600381111561461a5761461a61580f565b036146275750603c614684565b600285600381111561463b5761463b61580f565b036146525761464b603c80615593565b9050614684565b60038560038111156146665761466661580f565b0361468457614676603c80615593565b614681906018615593565b90505b606f60008b6001600160a01b03166001600160a01b031681526020019081526020016000206040518061012001604052808b81526020018a815260200189815260200183815260200188815260200188815260200142815260200160011515815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050835460018082018655948252602091829020845160099092020190815590830151938101939093555060408101516002830155606081015160038301556080810151600483015560a0810151600583015560c0810151600683015560e081015160078301805460ff191691151591909117905561010081015190919060088201906147ab9082615870565b5050506001600160a01b038a166000818152606f6020526040902080547f1d50952dd79441da39cded51d73c41faef52bb4929b6f9d51cc0e004842630e2918591829081106147fc576147fc615567565b9060005260206000209060090201604051614818929190615930565b60405180910390a25098975050505050505050565b604051627eeac760e11b81526001600160a01b03878116600483015260248201869052600091829188169062fdd58e90604401602060405180830381865afa15801561487d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148a1919061554e565b6001600160a01b03808a166000908152607360209081526040808320938c1683529281528282208a8352905290812054919250906148e1908686856140e6565b6001600160a01b03808b166000908152607360209081526040808320938d1683529281528282208b8352905290812054919250906149219087878a6140e6565b905061492d8784615797565b600003614969576001600160a01b03808b166000908152607360209081526040808320938d1683529281528282208b83529052908120556149c5565b60006149896149788385615797565b88886149848c89615797565b613bbb565b905061499581426157aa565b6001600160a01b03808d166000908152607360209081526040808320938f1683529281528282208d835290522055505b9998505050505050505050565b600054610100900460ff166149f95760405162461bcd60e51b81526004016111be90615825565b6125ff33614129565b6001600160a01b038116811461370b57600080fd5b8035614a2281614a02565b919050565b801515811461370b57600080fd5b8035614a2281614a27565b60008060408385031215614a5357600080fd5b8235614a5e81614a02565b91506020830135614a6e81614a27565b809150509250929050565b600060208284031215614a8b57600080fd5b8135614a9681614a02565b9392505050565b6000815180845260005b81811015614ac357602081850181015186830182015201614aa7565b506000602082860101526020601f19601f83011685010191505092915050565b87815260e060208201526000614afc60e0830189614a9d565b8281036040840152614b0e8189614a9d565b90508281036060840152614b228188614a9d565b90508281036080840152614b368187614a9d565b94151560a0840152505090151560c09091015295945050505050565b600080600060608486031215614b6757600080fd5b8335614b7281614a02565b92506020840135614b8281614a02565b91506040840135614b9281614a02565b809150509250925092565b60008060408385031215614bb057600080fd5b8235614bbb81614a02565b946020939093013593505050565b60008060008060808587031215614bdf57600080fd5b84359350602085013592506040850135614bf881614a02565b9396929550929360600135925050565b60008060008060008060c08789031215614c2157600080fd5b8635955060208701359450604087013593506060870135614c4181614a02565b92506080870135614c5181614a02565b8092505060a087013590509295509295509295565b600060208284031215614c7857600080fd5b5035919050565b60008083601f840112614c9157600080fd5b50813567ffffffffffffffff811115614ca957600080fd5b602083019150836020828501011115614cc157600080fd5b9250929050565b600080600060408486031215614cdd57600080fd5b8335614ce881614a02565b9250602084013567ffffffffffffffff811115614d0457600080fd5b614d1086828701614c7f565b9497909650939450505050565b600080600060608486031215614d3257600080fd5b8335614d3d81614a02565b9250602084013591506040840135614b9281614a27565b600080600060608486031215614d6957600080fd5b8335614d7481614a02565b95602085013595506040909401359392505050565b60008060408385031215614d9c57600080fd5b8235614da781614a02565b91506020830135614a6e81614a02565b60006101208b83528a60208401528960408401528860608401528760808401528660a08401528560c084015284151560e084015280610100840152614dfe81840185614a9d565b9c9b505050505050505050505050565b60008083601f840112614e2057600080fd5b50813567ffffffffffffffff811115614e3857600080fd5b6020830191508360208260051b8501011115614cc157600080fd5b600080600080600080600060a0888a031215614e6e57600080fd5b8735614e7981614a02565b9650602088013567ffffffffffffffff80821115614e9657600080fd5b614ea28b838c01614e0e565b909850965060408a01359150614eb782614a02565b909450606089013590614ec982614a02565b90935060808901359080821115614edf57600080fd5b50614eec8a828b01614e0e565b989b979a50959850939692959293505050565b60008060008060808587031215614f1557600080fd5b8435614f2081614a02565b93506020850135614f3081614a02565b93969395505050506040820135916060013590565b60008060008060608587031215614f5b57600080fd5b8435614f6681614a02565b9350602085013567ffffffffffffffff811115614f8257600080fd5b614f8e87828801614e0e565b9094509250506040850135614fa281614a27565b939692955090935050565b60008060008060608587031215614fc357600080fd5b8435614fce81614a02565b935060208501359250604085013567ffffffffffffffff811115614ff157600080fd5b614ffd87828801614c7f565b95989497509550505050565b60008060006060848603121561501e57600080fd5b833561502981614a02565b9250602084013591506040840135614b9281614a02565b600080600080600080600080600080600060e08c8e03121561506157600080fd5b61506a8c614a17565b9a5067ffffffffffffffff8060208e0135111561508657600080fd5b6150968e60208f01358f01614c7f565b909b50995060408d01358110156150ac57600080fd5b6150bc8e60408f01358f01614c7f565b909950975060608d01358110156150d257600080fd5b6150e28e60608f01358f01614c7f565b909750955060808d01358110156150f857600080fd5b506151098d60808e01358e01614c7f565b909450925060a08c0135915061512160c08d01614a35565b90509295989b509295989b9093969950565b60008060006060848603121561514857600080fd5b833561515381614a02565b9250602084013561516381614a02565b929592945050506040919091013590565b60008060008060008060008060006101208a8c03121561519357600080fd5b893561519e81614a02565b985060208a01356151ae81614a02565b975060408a0135965060608a01356151c581614a02565b955060808a0135945060a08a0135935060c08a0135925060e08a01356151ea81614a02565b91506101008a01356151fb81614a02565b809150509295985092959850929598565b803560048110614a2257600080fd5b60008060008060008060008060e0898b03121561523757600080fd5b883561524281614a02565b97506020890135965060408901359550606089013594506080890135935061526c60a08a0161520c565b925060c089013567ffffffffffffffff81111561528857600080fd5b6152948b828c01614c7f565b999c989b5096995094979396929594505050565b600080600080608085870312156152be57600080fd5b84356152c981614a02565b935060208501359250614bf86040860161520c565b6000806000806000806000806080898b0312156152fa57600080fd5b883567ffffffffffffffff8082111561531257600080fd5b61531e8c838d01614e0e565b909a50985060208b013591508082111561533757600080fd5b6153438c838d01614e0e565b909850965060408b013591508082111561535c57600080fd5b6153688c838d01614e0e565b909650945060608b013591508082111561538157600080fd5b506152948b828c01614e0e565b600080600080600060a086880312156153a657600080fd5b85356153b181614a02565b945060208601356153c181614a02565b9350604086013592506060860135915060808601356153df81614a02565b809150509295509295909350565b600181811c9082168061540157607f821691505b60208210810361542157634e487b7160e01b600052602260045260246000fd5b50919050565b60008154615434816153ed565b808552602060018381168015615451576001811461546b57615499565b60ff1985168884015283151560051b880183019550615499565b866000528260002060005b858110156154915781548a8201860152908301908401615476565b890184019650505b505050505092915050565b8054825260e0602083015260006154c160e0840160018401615427565b83810360408501526154d68160028501615427565b905083810360608501526154ed8160038501615427565b905083810360808501526155048160048501615427565b9050600583015460ff8116151560a086015261552a60c0860160ff8360081c1615159052565b509392505050565b60ff83168152604060208201526000610ed560408301846154a4565b60006020828403121561556057600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610fd357610fd361557d565b634e487b7160e01b600052604160045260246000fd5b601f82111561185f57600081815260208120601f850160051c810160208610156155e75750805b601f850160051c820191505b81811015615606578281556001016155f3565b505050505050565b67ffffffffffffffff831115615626576156266155aa565b61563a8361563483546153ed565b836155c0565b6000601f84116001811461566e57600085156156565750838201355b600019600387901b1c1916600186901b178355611ca3565b600083815260209020601f19861690835b8281101561569f578685013582556020948501946001909201910161567f565b50868210156156bc5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006101208254845260018301546020850152600283015460408501526003830154606085015260048301546080850152600583015460a0850152600683015460c0850152615721600784015460ff1690565b151560e08501526101008401819052610ed581850160088501615427565b83815260ff83166020820152606060408201526000613bdb60608301846156ce565b6000600182016157735761577361557d565b5060010190565b60006020828403121561578c57600080fd5b8151614a9681614a27565b81810381811115610fd357610fd361557d565b80820180821115610fd357610fd361557d565b6000826157da57634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156157f157600080fd5b8151614a9681614a02565b602081526000614a9660208301846154a4565b634e487b7160e01b600052602160045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b815167ffffffffffffffff81111561588a5761588a6155aa565b61589e8161589884546153ed565b846155c0565b602080601f8311600181146158d357600084156158bb5750858301515b600019600386901b1c1916600185901b178555615606565b600085815260208120601f198616915b82811015615902578886015182559484019460019091019084016158e3565b50858210156159205787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b828152604060208201526000610ed560408301846156ce56fe5fff5779f55d71041c8a8dac64fd1d4394cf4b41d7ef502baf7bbeabad381b37be670b8146f19d76b44fcaf05a819ec7dfe1d8265e48858e044fbed8126b0a23a2646970667358221220e6af59b87b4cc7646ac1b838eedb18bafe8df2c1b610dc63fc557a354bf136d064736f6c63430008110033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106104535760003560e01c8063715018a611610241578063bc302c881161013b578063ec9cd925116100c3578063fbdfc81511610087578063fbdfc81514610a92578063fc113aa514610aa5578063fca6bab014610ab8578063fdd264fb14610acb578063fe8020ba14610aff57600080fd5b8063ec9cd92514610a27578063ee01e5e714610a3a578063f2fde38b14610a43578063f3598ad914610a56578063f77c479114610a7f57600080fd5b8063ca5f81b51161010a578063ca5f81b5146109b4578063cd6740e5146109c7578063d78a3845146109f8578063de14e54d14610a01578063e63f366414610a1457600080fd5b8063bc302c8814610968578063bd2127841461097b578063bdb343721461098e578063be1f7828146109a157600080fd5b80638f5c81a1116101c9578063a526d83b1161018d578063a526d83b146108d8578063a54bc0b2146108eb578063abcac6bc146108fe578063b4a90fc71461092f578063b54d01da1461096057600080fd5b80638f5c81a11461086e578063923313771461088157806392eefe9b146108aa5780639da254ad146108bd578063a39dc9be146108d057600080fd5b806385cc313c1161021057806385cc313c146107f657806389d29297146108095780638ab656861461081c5780638d57c2031461082f5780638da5cb5b1461085d57600080fd5b8063715018a6146107c957806372539511146107d15780637c25509d146107e4578063800375a7146107ed57600080fd5b806335fa4384116103525780634cf31905116102da5780635e31b0731161029e5780635e31b07314610749578063667d3fb41461075c5780636cf667d41461076f5780636e2a42651461078257806371404156146107b657600080fd5b80634cf31905146106f4578063512f87781461070757806354fd4d501461071a5780635879fa92146107235780635b8afb701461073657600080fd5b806344ab1ee81161032157806344ab1ee814610662578063462b972514610675578063479f43651461068857806348d378561461069b578063497adbcb146106c657600080fd5b806335fa4384146105f1578063399ef453146106045780633af32abf1461062c5780634390c4ee1461064f57600080fd5b80631c89382a116103e05780632896f60b116103a45780632896f60b1461059257806328b047c8146105a557806328edec8e146105b85780633121db1c146105cb57806334a07d10146105de57600080fd5b80631c89382a1461053e5780631d21d4d9146105515780631ee9211f146105645780632750738f1461057757806327cfe8561461058a57600080fd5b806314f2101f1161042757806314f2101f146104da578063183e1a24146104fd578063197a2a7714610510578063198a8f65146105235780631ab3995a1461052b57600080fd5b80621f8a8b1461045857806305a9e0731461046d578063092d79c21461049d57806310bfbaea146104c3575b600080fd5b61046b610466366004614a40565b610b2a565b005b606554610480906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b6104b06104ab366004614a79565b610c15565b6040516104949796959493929190614ae3565b6104cc606a5481565b604051908152602001610494565b6104ed6104e8366004614b52565b610e76565b6040519015158152602001610494565b6104cc61050b366004614b9d565b610edd565b6104ed61051e366004614bc9565b610fd9565b6104cc603c81565b61046b610539366004614b9d565b611033565b61046b61054c366004614a79565b6110fb565b61046b61055f366004614c08565b611125565b6104cc610572366004614b9d565b61128c565b61046b610585366004614c66565b6112d0565b6104cc6112fe565b6104ed6105a0366004614a79565b611317565b61046b6105b3366004614cc8565b61135c565b61046b6105c6366004614d1d565b61145a565b61046b6105d9366004614cc8565b611596565b61046b6105ec366004614d54565b611685565b61046b6105ff366004614d89565b611793565b610617610612366004614b9d565b611864565b60405161049499989796959493929190614db7565b6104ed61063a366004614a79565b606b6020526000908152604090205460ff1681565b61046b61065d366004614e53565b611964565b61046b610670366004614d54565b611a5a565b6104cc610683366004614b9d565b611b7d565b61046b610696366004614d54565b611bc1565b6104cc6106a9366004614b9d565b607260209081526000928352604080842090915290825290205481565b6104ed6106d4366004614d89565b606d60209081526000928352604080842090915290825290205460ff1681565b61046b610702366004614c66565b611caa565b61046b610715366004614eff565b611cb7565b6104cc60785481565b61046b610731366004614cc8565b612131565b61046b610744366004614c66565b612220565b61046b610757366004614f45565b61222d565b6104cc61076a366004614b9d565b612340565b61046b61077d366004614fad565b61243b565b610480610790366004614d89565b60776020908152600092835260408084209091529082529020546001600160a01b031681565b61046b6107c4366004614a79565b612584565b61046b6125ed565b6104cc6107df366004614b9d565b612601565b6104cc60685481565b6104cc60695481565b61046b610804366004614d54565b61262b565b61046b610817366004614eff565b612771565b61046b61082a366004614d89565b612afe565b6104ed61083d366004614d89565b607660209081526000928352604080842090915290825290205460ff1681565b6033546001600160a01b0316610480565b61046b61087c366004615009565b612b53565b6104cc61088f366004614a79565b6001600160a01b03166000908152606f602052604090205490565b61046b6108b8366004614a79565b612d22565b61046b6108cb366004615040565b612d4c565b6104cc612e8c565b61046b6108e6366004614a79565b612e97565b61046b6108f9366004614d89565b612f18565b6104cc61090c366004615133565b607360209081526000938452604080852082529284528284209052825290205481565b6104cc61093d366004615133565b607060209081526000938452604080852082529284528284209052825290205481565b6104cc600181565b61046b610976366004615174565b612f61565b6104cc61098936600461521b565b613395565b61046b61099c366004614c66565b613443565b6104cc6109af366004614b9d565b613450565b61046b6109c2366004614c66565b61347a565b6104cc6109d5366004615133565b607560209081526000938452604080852082529284528284209052825290205481565b6104cc60675481565b61046b610a0f366004614a40565b613487565b6104ed610a22366004614b9d565b61355e565b61046b610a35366004614cc8565b6135a6565b6104cc61271081565b61046b610a51366004614a79565b613695565b610480610a64366004614a79565b606e602052600090815260409020546001600160a01b031681565b606654610480906001600160a01b031681565b61046b610aa03660046152a8565b61370e565b61046b610ab33660046152de565b613968565b61046b610ac636600461538e565b613a0d565b610480610ad9366004614b9d565b60716020908152600092835260408084209091529082529020546001600160a01b031681565b6104cc610b0d366004614b9d565b607460209081526000928352604080842090915290825290205481565b6001600160a01b0382166000908152606b6020526040902054829060ff16610b65576040516371d42f3560e11b815260040160405180910390fd5b82610b786033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614610bb957336001600160a01b03821614610bb9576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0384166000818152606c60205260409081902060058101805461ff00191661010088151502179055905160008051602061594a83398151915291610c079160049190615532565b60405180910390a250505050565b606c6020526000908152604090208054600182018054919291610c37906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610c63906153ed565b8015610cb05780601f10610c8557610100808354040283529160200191610cb0565b820191906000526020600020905b815481529060010190602001808311610c9357829003601f168201915b505050505090806002018054610cc5906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610cf1906153ed565b8015610d3e5780601f10610d1357610100808354040283529160200191610d3e565b820191906000526020600020905b815481529060010190602001808311610d2157829003601f168201915b505050505090806003018054610d53906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610d7f906153ed565b8015610dcc5780601f10610da157610100808354040283529160200191610dcc565b820191906000526020600020905b815481529060010190602001808311610daf57829003601f168201915b505050505090806004018054610de1906153ed565b80601f0160208091040260200160405190810160405280929190818152602001828054610e0d906153ed565b8015610e5a5780601f10610e2f57610100808354040283529160200191610e5a565b820191906000526020600020905b815481529060010190602001808311610e3d57829003601f168201915b5050506005909301549192505060ff8082169161010090041687565b6001600160a01b0383811660009081526077602090815260408083208585168452909152812054909184811691161480610ed557506001600160a01b0380851660009081526076602090815260408083209387168352929052205460ff165b949350505050565b60405163bd85b03960e01b8152600481018290526000906001600160a01b0384169063bd85b03990602401602060405180830381865afa158015610f25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f49919061554e565b600003610f6957604051633b41868f60e21b815260040160405180910390fd5b6001600160a01b0380841660008181526071602090815260408083208784528252808320549094168252606f8152838220928252607281528382208683529052919091205481548110610fbe57610fbe615567565b90600052602060002090600902016004015490505b92915050565b600080610fe68484612601565b90506000610ff48585613450565b905081600003611017576040516333adb20360e11b815260040160405180910390fd5b61102387838389613bbb565b606a541115979650505050505050565b6001600160a01b0382166000908152606b6020526040902054829060ff1661106e576040516371d42f3560e11b815260040160405180910390fd5b826110816033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146110c257336001600160a01b038216146110c2576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0384166000818152606c6020526040808220868155905160008051602061594a83398151915292610c07929091615532565b611103613be4565b606580546001600160a01b0319166001600160a01b0392909216919091179055565b600054610100900460ff16158080156111455750600054600160ff909116105b8061115f5750303b15801561115f575060005460ff166001145b6111c75760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff1916600117905580156111ea576000805461ff0019166101001790555b6111f2613c3e565b6067879055606886905560698590556276a700606a55606580546001600160a01b038087166001600160a01b031992831617909255606680549286169290911691909117905560788290558015611283576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b6001600160a01b0382166000908152606f602052604081208054839081106112b6576112b6615567565b906000526020600020906009020160020154905092915050565b6112d8613be4565b806000036112f957604051637beed6ff60e11b815260040160405180910390fd5b606a55565b611309603c80615593565b611314906018615593565b81565b6001600160a01b0381166000908152606b602052604081205460ff168015610fd35750506001600160a01b03166000908152606c602052604090206005015460ff1690565b6001600160a01b0383166000908152606b6020526040902054839060ff16611397576040516371d42f3560e11b815260040160405180910390fd5b836113aa6033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146113eb57336001600160a01b038216146113eb576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c6020526040902060010161141184868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160019190615532565b60405180910390a25050505050565b6001600160a01b0383166000908152606b6020526040902054839060ff16611495576040516371d42f3560e11b815260040160405180910390fd5b836114a86033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146114e957336001600160a01b038216146114e9576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f6020526040902080548491908690811061151657611516615567565b6000918252602080832060076009909302018201805494151560ff19909516949094179093556001600160a01b038816808352606f9093526040909120805460008051602061596a83398151915292889290918390811061157957611579615567565b906000526020600020906009020160405161144b9392919061573f565b6001600160a01b0383166000908152606b6020526040902054839060ff166115d1576040516371d42f3560e11b815260040160405180910390fd5b836115e46033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461162557336001600160a01b03821614611625576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c6020526040902060020161164b84868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160029190615532565b6001600160a01b0383166000908152606b6020526040902054839060ff166116c0576040516371d42f3560e11b815260040160405180910390fd5b836116d36033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461171457336001600160a01b03821614611714576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f6020526040902080548491908690811061174157611741615567565b600091825260208083206009909202909101929092556001600160a01b038716808252606f90925260408120805460008051602061596a83398151915292889290918390811061157957611579615567565b336000818152606b602052604090205460ff166117c3576040516371d42f3560e11b815260040160405180910390fd5b6001600160a01b038216611817576000607681335b6001600160a01b03908116825260208083019390935260409182016000908120918816815292529020805491151560ff19909216919091179055505050565b6000607781335b6001600160a01b039081168252602080830193909352604091820160009081208783168252909352912080546001600160a01b031916929091169190911790555b505050565b606f602052816000526040600020818154811061188057600080fd5b9060005260206000209060090201600091509150508060000154908060010154908060020154908060030154908060040154908060050154908060060154908060070160009054906101000a900460ff16908060080180546118e1906153ed565b80601f016020809104026020016040519081016040528092919081815260200182805461190d906153ed565b801561195a5780601f1061192f5761010080835404028352916020019161195a565b820191906000526020600020905b81548152906001019060200180831161193d57829003601f168201915b5050505050905089565b61196c613be4565b61197584611317565b1561199357604051634c620c3f60e11b815260040160405180910390fd5b61199c83611317565b6119b95760405163cedb19a160e01b815260040160405180910390fd5b60005b85811015611a50576119e6848484848181106119da576119da615567565b9050602002013561355e565b611a03576040516339cf183d60e11b815260040160405180910390fd5b611a4088888884818110611a1957611a19615567565b905060200201358787878787818110611a3457611a34615567565b90506020020135613c6d565b611a4981615761565b90506119bc565b5050505050505050565b6001600160a01b0383166000908152606b6020526040902054839060ff16611a95576040516371d42f3560e11b815260040160405180910390fd5b83611aa86033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614611ae957336001600160a01b03821614611ae9576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f60205260409020805484919086908110611b1657611b16615567565b906000526020600020906009020160020181905550846001600160a01b031660008051602061596a833981519152856002606f60008a6001600160a01b03166001600160a01b03168152602001908152602001600020888154811061157957611579615567565b6001600160a01b0382166000908152606f60205260408120805483908110611ba757611ba7615567565b906000526020600020906009020160010154905092915050565b6001600160a01b0383166000908152606b6020526040902054839060ff16611bfc576040516371d42f3560e11b815260040160405180910390fd5b83611c0f6033546001600160a01b031690565b6001600160a01b0316336001600160a01b031614611c5057336001600160a01b03821614611c50576040516305fa117f60e11b815260040160405180910390fd5b611ca3858585606f60008a6001600160a01b03166001600160a01b031681526020019081526020016000208881548110611c8c57611c8c615567565b906000526020600020906009020160030154613d6c565b5050505050565b611cb2613be4565b606955565b6066546001600160a01b031663aee3d144336040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015611d0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d33919061577a565b1580611db857506066546001600160a01b031663236d64a3336040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024016020604051808303816000875af1158015611d92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db6919061577a565b155b15611dd657604051632ed58dfb60e21b815260040160405180910390fd5b336000611de38285610edd565b90506000611df18386612340565b6001600160a01b038089166000908152607360209081526040808320938816835292815282822089835290529081205491925090611e31908484886140e6565b6001600160a01b03808a166000818152607360209081526040808320948a168084529482528083208c8452909152808220549051627eeac760e11b81526004810193909352602483018b905293945092611eda9290918791879162fdd58e906044015b602060405180830381865afa158015611eb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ed5919061554e565b6140e6565b6001600160a01b03808a166000818152607360209081526040808320948b168084529482528083208d8452909152808220549051627eeac760e11b81526004810193909352602483018c905293945092611f419290918891889162fdd58e90604401611e94565b604051627eeac760e11b81526001600160a01b038c81166004830152602482018b905291925060009189919089169062fdd58e90604401602060405180830381865afa158015611f95573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fb9919061554e565b611fc39190615797565b905080600003612002576001600160a01b03808c166000908152607360209081526040808320938b1683529281528282208c8352905290812055612050565b61201761200f8585615797565b878784613bbb565b61202190426157aa565b6001600160a01b03808d166000908152607360209081526040808320938c1683529281528282208d8352905220555b604051627eeac760e11b81526001600160a01b038b81166004830152602482018b90526000918a918a169062fdd58e90604401602060405180830381865afa1580156120a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120c4919061554e565b6120ce91906157aa565b90506120e56120dd86856157aa565b888884613bbb565b6120ef90426157aa565b6001600160a01b039b8c1660009081526073602090815260408083209b909e168252998a528c81209b81529a9098525050509690952092909255505050505050565b6001600160a01b0383166000908152606b6020526040902054839060ff1661216c576040516371d42f3560e11b815260040160405180910390fd5b8361217f6033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146121c057336001600160a01b038216146121c0576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c602052604090206003016121e684868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160039190615532565b612228613be4565b606755565b6001600160a01b0384166000908152606b6020526040902054849060ff16612268576040516371d42f3560e11b815260040160405180910390fd5b8461227b6033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146122bc57336001600160a01b038216146122bc576040516305fa117f60e11b815260040160405180910390fd5b60005b84811015611283576001600160a01b0387166000908152606d6020526040812085918888858181106122f3576122f3615567565b90506020020160208101906123089190614a79565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905561233981615761565b90506122bf565b60405163bd85b03960e01b8152600481018290526000906001600160a01b0384169063bd85b03990602401602060405180830381865afa158015612388573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ac919061554e565b6000036123cc57604051633b41868f60e21b815260040160405180910390fd5b6001600160a01b0380841660008181526071602090815260408083208784528252808320549094168252606f815283822092825260728152838220868352905291909120548154811061242157612421615567565b906000526020600020906009020160030154905092915050565b6001600160a01b0384166000908152606b6020526040902054849060ff16612476576040516371d42f3560e11b815260040160405180910390fd5b846124896033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146124ca57336001600160a01b038216146124ca576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0386166000908152606f60205260409020805485918591889081106124f8576124f8615567565b9060005260206000209060090201600801918261251692919061560e565b506001600160a01b0386166000818152606f60205260409020805460008051602061596a833981519152918891600891908390811061255757612557615567565b90600052602060002090600902016040516125749392919061573f565b60405180910390a2505050505050565b61258c613be4565b6001600160a01b0381166000818152606b60209081526040808320805460ff19908116909155606c9092528083206005018054909216909155517fb8107d0c6b40be480ce3172ee66ba6d64b71f6b1685a851340036e6e2e3e3c529190a250565b6125f5613be4565b6125ff6000614129565b565b6001600160a01b0382166000908152606f60205260408120805483908110610fbe57610fbe615567565b6001600160a01b0383166000908152606b6020526040902054839060ff16612666576040516371d42f3560e11b815260040160405180910390fd5b836126796033546001600160a01b031690565b6001600160a01b0316336001600160a01b0316146126ba57336001600160a01b038216146126ba576040516305fa117f60e11b815260040160405180910390fd5b6067548310156126dd5760405163522036bf60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606f6020526040902080548491908690811061270a5761270a615567565b906000526020600020906009020160010181905550846001600160a01b031660008051602061596a833981519152856001606f60008a6001600160a01b03166001600160a01b03168152602001908152602001600020888154811061157957611579615567565b604051627eeac760e11b81526001600160a01b038481166004830152602482018490526000919086169062fdd58e90604401602060405180830381865afa1580156127c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127e4919061554e565b6001600160a01b038087166000818152607160209081526040808320898452825280832054938352607282528083208984529091528120549394509116919061282d8383612601565b905080600003612850576040516333adb20360e11b815260040160405180910390fd5b84600003612871576040516306c95d7d60e41b815260040160405180910390fd5b83600003612892576040516369bdf96560e11b815260040160405180910390fd5b6001600160a01b0383166128b95760405163137849f160e11b815260040160405180910390fd5b60006128d086836128ca8787613450565b88613bbb565b6001600160a01b03808a166000908152607360209081526040808320938e1683529281528282208b83529052908120805492935083929091906129149084906157aa565b9091555050604080518281526001600160a01b038a811660208301528b81168284015291519186169189917f29de542d58d5280b82118289d7236d2b096f3e56797fd3bc4228f19a3c476947919081900360600190a3506065546001600160a01b031663348709b4866129878686613450565b6129918886615593565b61299b91906157bd565b86607360008d6001600160a01b03166001600160a01b0316815260200190815260200160002060008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008c8152602001908152602001600020546129fd3390565b606660009054906101000a90046001600160a01b03166001600160a01b0316633013ce296040518163ffffffff1660e01b81526004016020604051808303816000875af1158015612a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7691906157df565b6040516001600160e01b031960e089901b168152600481019690965260248601949094526001600160a01b0392831660448601526064850191909152811660848401521660a482015260c401600060405180830381600087803b158015612adc57600080fd5b505af1158015612af0573d6000803e3d6000fd5b505050505050505050505050565b336000818152606b602052604090205460ff16612b2e576040516371d42f3560e11b815260040160405180910390fd5b6001600160a01b038216612b4857600160766000336117d8565b82607760003361181e565b6001600160a01b038381166000908152607160209081526040808320868452909152902054163314612b985760405163bc1a99ad60e01b815260040160405180910390fd5b612ba28383610edd565b600003612bc25760405163da9335d560e01b815260040160405180910390fd5b6001600160a01b0380821660009081526073602090815260408083209387168352928152828220858352905220544211612c0f576040516341f6b9a560e01b815260040160405180910390fd5b604051627eeac760e11b81526001600160a01b038281166004830152602482018490526000919085169062fdd58e90604401602060405180830381865afa158015612c5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c82919061554e565b905080600003612ca5576040516305319efb60e41b815260040160405180910390fd5b6001600160a01b0382811660009081526075602090815260408083209388168084529382528083208784529091529020805490839055903390857feef808aafa779451f3107a5033b5d50922fbd85286781c04ba9a3a88b7f27d77612d0a8587615797565b60405190815260200160405180910390a45050505050565b612d2a613be4565b606680546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038b166000908152606c6020526040902060058101805460ff19166001179055600201612d818a8c8361560e565b506001600160a01b038b166000908152606c60205260409020600101612da8888a8361560e565b506001600160a01b038b166000908152606c60205260409020600401612dcf86888361560e565b506001600160a01b038b166000908152606c6020526040902060058101805461ff00191661010084151502179055600301612e0b84868361560e565b506001600160a01b038b166000908152606c60205260409020829055612e308b612e97565b6001600160a01b038b166000818152606c60205260409081902090517f40a85abf2e067de420759997226b243a11146e32797c459e0ae521c164b3ef7c91612e77916157fc565b60405180910390a25050505050505050505050565b611314603c80615593565b612e9f613be4565b6001600160a01b0381166000818152606b602090815260408083208054600160ff199182168117909255606c90935292819020600581018054909316909317909155517fa08c78c5ffa2e84c547405de8308d3981bfc147bbe8186049de946adf23bedf291612f0d916157fc565b60405180910390a250565b612f20613be4565b60005b6001600160a01b0383166000908152606f602052604090205481101561185f57612f4e83838361417b565b5080612f5981615761565b915050612f23565b6066546001600160a01b0316336001600160a01b031614612f9557604051632d5fb10f60e01b815260040160405180910390fd5b6001600160a01b038087166000908152607060209081526040808320938d1683529281528282208a835290529081208054859290612fd49084906157aa565b90915550506001600160a01b0389811660008181526071602090815260408083208c8452825280832080546001600160a01b031916958c169586179055928252607281528282208b83528152828220899055928152606f909252812080548790811061304257613042615567565b906000526020600020906009020160040154111561338a576001600160a01b038089166000908152607360209081526040808320938d1683529281528282208a835290529081205490036130c1576001600160a01b038089166000908152607360209081526040808320938d1683529281528282208a83529052204290555b6001600160a01b0386166000908152606f602052604081208054613151918791899081106130f1576130f1615567565b906000526020600020906009020160040154606f60008b6001600160a01b03166001600160a01b03168152602001908152602001600020898154811061313957613139615567565b90600052602060002090600902016003015487613bbb565b6001600160a01b03808b166000908152607360209081526040808320938f1683529281528282208c83529052908120805492935083929091906131959084906157aa565b9091555050604080518281526001600160a01b038b811660208301528c8116828401529151918916918a917f29de542d58d5280b82118289d7236d2b096f3e56797fd3bc4228f19a3c476947919081900360600190a3506065546001600160a01b031663348709b4856132088989613450565b6001600160a01b038a166000908152606f6020526040902080548891908b90811061323557613235615567565b9060005260206000209060090201600401546132519190615593565b61325b91906157bd565b89607360008e6001600160a01b03166001600160a01b0316815260200190815260200160002060008f6001600160a01b03166001600160a01b0316815260200190815260200160002060008d81526020019081526020016000205487876040518763ffffffff1660e01b815260040161330a9695949392919095865260208601949094526001600160a01b0392831660408601526060850191909152811660808401521660a082015260c00190565b600060405180830381600087803b15801561332457600080fd5b505af1158015613338573d6000803e3d6000fd5b505060408051888152602081018b90526001600160a01b038d8116828401529151918a1693507f9137dbe71594712b8c41002a261f3818dd6e951587d83c552606f4c53100f62b925081900360600190a25b505050505050505050565b6001600160a01b0388166000908152606b6020526040812054899060ff166133d0576040516371d42f3560e11b815260040160405180910390fd5b896133e36033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461342457336001600160a01b03821614613424576040516305fa117f60e11b815260040160405180910390fd5b6134348b8b8b8b8b8b8b8b6145cc565b9b9a5050505050505050505050565b61344b613be4565b606855565b6001600160a01b0382166000908152606f6020526040812080548390811061242157612421615567565b613482613be4565b607855565b6001600160a01b0382166000908152606b6020526040902054829060ff166134c2576040516371d42f3560e11b815260040160405180910390fd5b826134d56033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461351657336001600160a01b03821614613516576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0384166000818152606c6020526040908190206005808201805460ff1916881515179055915160008051602061594a83398151915292610c07929091615532565b6001600160a01b0382166000908152606f6020526040812080548390811061358857613588615567565b600091825260209091206009909102016007015460ff169392505050565b6001600160a01b0383166000908152606b6020526040902054839060ff166135e1576040516371d42f3560e11b815260040160405180910390fd5b836135f46033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461363557336001600160a01b03821614613635576040516305fa117f60e11b815260040160405180910390fd5b6001600160a01b0385166000908152606c6020526040902060040161365b84868361560e565b506001600160a01b0385166000818152606c602052604090819020905160008051602061594a8339815191529161144b9160049190615532565b61369d613be4565b6001600160a01b0381166137025760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016111be565b61370b81614129565b50565b6001600160a01b0384166000908152606b6020526040902054849060ff16613749576040516371d42f3560e11b815260040160405180910390fd5b8461375c6033546001600160a01b031690565b6001600160a01b0316336001600160a01b03161461379d57336001600160a01b0382161461379d576040516305fa117f60e11b815260040160405180910390fd5b6000808560038111156137b2576137b261580f565b036137bf5750600161383d565b60018560038111156137d3576137d361580f565b036137e05750603c61383d565b60028560038111156137f4576137f461580f565b0361380b57613804603c80615593565b905061383d565b600385600381111561381f5761381f61580f565b0361383d5761382f603c80615593565b61383a906018615593565b90505b6001600160a01b0387166000908152606f6020526040902080548291908890811061386a5761386a615567565b9060005260206000209060090201600301540361389a5760405163842cebc360e01b815260040160405180910390fd5b6138a687878684613d6c565b6001600160a01b0387166000908152606f602052604090208054829190889081106138d3576138d3615567565b906000526020600020906009020160030181905550866001600160a01b031660008051602061596a833981519152876003606f60008c6001600160a01b03166001600160a01b031681526020019081526020016000208a8154811061393a5761393a615567565b90600052602060002090600902016040516139579392919061573f565b60405180910390a250505050505050565b60005b8381101561338a576139fb89898381811061398857613988615567565b905060200201602081019061399d9190614a79565b8888848181106139af576139af615567565b90506020020160208101906139c49190614a79565b8787858181106139d6576139d6615567565b905060200201358686868181106139ef576139ef615567565b90506020020135612771565b80613a0581615761565b91505061396b565b6066546001600160a01b0316336001600160a01b031614613a4157604051632d5fb10f60e01b815260040160405180910390fd5b6001600160a01b0380821660009081526075602090815260408083209388168352928152828220868352905220548211613a8e5760405163481ae58160e01b815260040160405180910390fd5b6001600160a01b0384166000908152607260209081526040808320868452909152812054613abd908790612601565b6001600160a01b038616600090815260726020908152604080832088845290915281205491925090613af0908890613450565b90508115613b0857613b0683878787868661482d565b505b6001600160a01b038088166000908152607060209081526040808320938a16835292815282822088835290529081208054869290613b47908490615797565b90915550506001600160a01b038088166000908152607060209081526040808320938a168352928152828220888352905290812054900361128357505050506001600160a01b039190911660009081526071602090815260408083209383529290522080546001600160a01b031916905550565b6000613bc78285615593565b613bd18487615593565b613bdb91906157bd565b95945050505050565b6033546001600160a01b031633146125ff5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016111be565b600054610100900460ff16613c655760405162461bcd60e51b81526004016111be90615825565b6125ff6149d2565b6001600160a01b0380841660009081526070602081815260408084208a86168086529083528185208a865283528185208054908690559588168552928252808420928452918152818320888452905281208054839290613cce9084906157aa565b90915550506001600160a01b0386811660008181526071602090815260408083208a8452825280832080546001600160a01b031916898716908117909155848452607283528184208b855283529281902087905580518781529182018a9052810192909252918616907fa6beab620e184a03527e5ae53cfcf2bcc0a561f7fe957d28839a116e45ef70379060600160405180910390a3505050505050565b81600003613d8d576040516333adb20360e11b815260040160405180910390fd5b6001600160a01b0384166000908152606f60205260409020805484908110613db757613db7615567565b906000526020600020906009020160040154600003613de95760405163031fbaf760e41b815260040160405180910390fd5b6001600160a01b0384166000908152606f60205260408120805485908110613e1357613e13615567565b906000526020600020906009020160030154905080606f6000876001600160a01b03166001600160a01b031681526020019081526020016000208581548110613e5e57613e5e615567565b906000526020600020906009020160040154613e7a91906157bd565b613e8483856157bd565b1115613fbe576068546001600160a01b0386166000908152606f60205260409020805486908110613eb757613eb7615567565b906000526020600020906009020160060154613ed391906157aa565b421015613ef3576040516304caab9960e31b815260040160405180910390fd5b613eff61271082615593565b6069546001600160a01b0387166000908152606f60205260409020805487908110613f2c57613f2c615567565b906000526020600020906009020160040154613f489190615593565b613f5291906157bd565b613f5c83856157bd565b1115613f7b5760405163eb10300160e01b815260040160405180910390fd5b6001600160a01b0385166000908152606f60205260409020805442919086908110613fa857613fa8615567565b9060005260206000209060090201600601819055505b6001600160a01b0385166000908152606f60205260409020805484919086908110613feb57613feb615567565b90600052602060002090600902016004018190555080606f6000876001600160a01b03166001600160a01b03168152602001908152602001600020858154811061403757614037615567565b90600052602060002090600902016005015461405391906157bd565b61405d83856157bd565b10156140a6576001600160a01b0385166000908152606f6020526040902080548491908690811061409057614090615567565b9060005260206000209060090201600501819055505b6001600160a01b0385166000818152606f60205260409020805460008051602061596a833981519152918791600491908390811061157957611579615567565b60004285116140f757506000610ed5565b8282856141044289615797565b61410e9190615593565b6141189190615593565b61412291906157bd565b9050610ed5565b603380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b038083166000908152606f602052604080822080548251610120810184529488168452919092208054919391829190869081106141c1576141c1615567565b9060005260206000209060090201600001548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061420e5761420e615567565b9060005260206000209060090201600101548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061425b5761425b615567565b9060005260206000209060090201600201548152602001606f6000886001600160a01b03166001600160a01b0316815260200190815260200160002085815481106142a8576142a8615567565b9060005260206000209060090201600301548152602001606f6000886001600160a01b03166001600160a01b0316815260200190815260200160002085815481106142f5576142f5615567565b9060005260206000209060090201600401548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061434257614342615567565b9060005260206000209060090201600501548152602001606f6000886001600160a01b03166001600160a01b03168152602001908152602001600020858154811061438f5761438f615567565b9060005260206000209060090201600601548152602001606f6000886001600160a01b03166001600160a01b0316815260200190815260200160002085815481106143dc576143dc615567565b600091825260208083206007600990930201919091015460ff16151583526001600160a01b0389168252606f81526040909120805492909101918690811061442657614426615567565b90600052602060002090600902016008018054614442906153ed565b80601f016020809104026020016040519081016040528092919081815260200182805461446e906153ed565b80156144bb5780601f10614490576101008083540402835291602001916144bb565b820191906000526020600020905b81548152906001019060200180831161449e57829003601f168201915b50505091909252505081546001808201845560009384526020938490208351600990930201918255928201519281019290925560408101516002830155606081015160038301556080810151600483015560a0810151600583015560c0810151600683015560e081015160078301805460ff191691151591909117905561010081015190919060088201906145509082615870565b5050506001600160a01b0383166000818152606f6020526040902080547f1d50952dd79441da39cded51d73c41faef52bb4929b6f9d51cc0e004842630e2918491829081106145a1576145a1615567565b90600052602060002090600902016040516145bd929190615930565b60405180910390a29392505050565b6001600160a01b0388166000908152606f602052604081205490808560038111156145f9576145f961580f565b0361460657506001614684565b600185600381111561461a5761461a61580f565b036146275750603c614684565b600285600381111561463b5761463b61580f565b036146525761464b603c80615593565b9050614684565b60038560038111156146665761466661580f565b0361468457614676603c80615593565b614681906018615593565b90505b606f60008b6001600160a01b03166001600160a01b031681526020019081526020016000206040518061012001604052808b81526020018a815260200189815260200183815260200188815260200188815260200142815260200160011515815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920182905250939094525050835460018082018655948252602091829020845160099092020190815590830151938101939093555060408101516002830155606081015160038301556080810151600483015560a0810151600583015560c0810151600683015560e081015160078301805460ff191691151591909117905561010081015190919060088201906147ab9082615870565b5050506001600160a01b038a166000818152606f6020526040902080547f1d50952dd79441da39cded51d73c41faef52bb4929b6f9d51cc0e004842630e2918591829081106147fc576147fc615567565b9060005260206000209060090201604051614818929190615930565b60405180910390a25098975050505050505050565b604051627eeac760e11b81526001600160a01b03878116600483015260248201869052600091829188169062fdd58e90604401602060405180830381865afa15801561487d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906148a1919061554e565b6001600160a01b03808a166000908152607360209081526040808320938c1683529281528282208a8352905290812054919250906148e1908686856140e6565b6001600160a01b03808b166000908152607360209081526040808320938d1683529281528282208b8352905290812054919250906149219087878a6140e6565b905061492d8784615797565b600003614969576001600160a01b03808b166000908152607360209081526040808320938d1683529281528282208b83529052908120556149c5565b60006149896149788385615797565b88886149848c89615797565b613bbb565b905061499581426157aa565b6001600160a01b03808d166000908152607360209081526040808320938f1683529281528282208d835290522055505b9998505050505050505050565b600054610100900460ff166149f95760405162461bcd60e51b81526004016111be90615825565b6125ff33614129565b6001600160a01b038116811461370b57600080fd5b8035614a2281614a02565b919050565b801515811461370b57600080fd5b8035614a2281614a27565b60008060408385031215614a5357600080fd5b8235614a5e81614a02565b91506020830135614a6e81614a27565b809150509250929050565b600060208284031215614a8b57600080fd5b8135614a9681614a02565b9392505050565b6000815180845260005b81811015614ac357602081850181015186830182015201614aa7565b506000602082860101526020601f19601f83011685010191505092915050565b87815260e060208201526000614afc60e0830189614a9d565b8281036040840152614b0e8189614a9d565b90508281036060840152614b228188614a9d565b90508281036080840152614b368187614a9d565b94151560a0840152505090151560c09091015295945050505050565b600080600060608486031215614b6757600080fd5b8335614b7281614a02565b92506020840135614b8281614a02565b91506040840135614b9281614a02565b809150509250925092565b60008060408385031215614bb057600080fd5b8235614bbb81614a02565b946020939093013593505050565b60008060008060808587031215614bdf57600080fd5b84359350602085013592506040850135614bf881614a02565b9396929550929360600135925050565b60008060008060008060c08789031215614c2157600080fd5b8635955060208701359450604087013593506060870135614c4181614a02565b92506080870135614c5181614a02565b8092505060a087013590509295509295509295565b600060208284031215614c7857600080fd5b5035919050565b60008083601f840112614c9157600080fd5b50813567ffffffffffffffff811115614ca957600080fd5b602083019150836020828501011115614cc157600080fd5b9250929050565b600080600060408486031215614cdd57600080fd5b8335614ce881614a02565b9250602084013567ffffffffffffffff811115614d0457600080fd5b614d1086828701614c7f565b9497909650939450505050565b600080600060608486031215614d3257600080fd5b8335614d3d81614a02565b9250602084013591506040840135614b9281614a27565b600080600060608486031215614d6957600080fd5b8335614d7481614a02565b95602085013595506040909401359392505050565b60008060408385031215614d9c57600080fd5b8235614da781614a02565b91506020830135614a6e81614a02565b60006101208b83528a60208401528960408401528860608401528760808401528660a08401528560c084015284151560e084015280610100840152614dfe81840185614a9d565b9c9b505050505050505050505050565b60008083601f840112614e2057600080fd5b50813567ffffffffffffffff811115614e3857600080fd5b6020830191508360208260051b8501011115614cc157600080fd5b600080600080600080600060a0888a031215614e6e57600080fd5b8735614e7981614a02565b9650602088013567ffffffffffffffff80821115614e9657600080fd5b614ea28b838c01614e0e565b909850965060408a01359150614eb782614a02565b909450606089013590614ec982614a02565b90935060808901359080821115614edf57600080fd5b50614eec8a828b01614e0e565b989b979a50959850939692959293505050565b60008060008060808587031215614f1557600080fd5b8435614f2081614a02565b93506020850135614f3081614a02565b93969395505050506040820135916060013590565b60008060008060608587031215614f5b57600080fd5b8435614f6681614a02565b9350602085013567ffffffffffffffff811115614f8257600080fd5b614f8e87828801614e0e565b9094509250506040850135614fa281614a27565b939692955090935050565b60008060008060608587031215614fc357600080fd5b8435614fce81614a02565b935060208501359250604085013567ffffffffffffffff811115614ff157600080fd5b614ffd87828801614c7f565b95989497509550505050565b60008060006060848603121561501e57600080fd5b833561502981614a02565b9250602084013591506040840135614b9281614a02565b600080600080600080600080600080600060e08c8e03121561506157600080fd5b61506a8c614a17565b9a5067ffffffffffffffff8060208e0135111561508657600080fd5b6150968e60208f01358f01614c7f565b909b50995060408d01358110156150ac57600080fd5b6150bc8e60408f01358f01614c7f565b909950975060608d01358110156150d257600080fd5b6150e28e60608f01358f01614c7f565b909750955060808d01358110156150f857600080fd5b506151098d60808e01358e01614c7f565b909450925060a08c0135915061512160c08d01614a35565b90509295989b509295989b9093969950565b60008060006060848603121561514857600080fd5b833561515381614a02565b9250602084013561516381614a02565b929592945050506040919091013590565b60008060008060008060008060006101208a8c03121561519357600080fd5b893561519e81614a02565b985060208a01356151ae81614a02565b975060408a0135965060608a01356151c581614a02565b955060808a0135945060a08a0135935060c08a0135925060e08a01356151ea81614a02565b91506101008a01356151fb81614a02565b809150509295985092959850929598565b803560048110614a2257600080fd5b60008060008060008060008060e0898b03121561523757600080fd5b883561524281614a02565b97506020890135965060408901359550606089013594506080890135935061526c60a08a0161520c565b925060c089013567ffffffffffffffff81111561528857600080fd5b6152948b828c01614c7f565b999c989b5096995094979396929594505050565b600080600080608085870312156152be57600080fd5b84356152c981614a02565b935060208501359250614bf86040860161520c565b6000806000806000806000806080898b0312156152fa57600080fd5b883567ffffffffffffffff8082111561531257600080fd5b61531e8c838d01614e0e565b909a50985060208b013591508082111561533757600080fd5b6153438c838d01614e0e565b909850965060408b013591508082111561535c57600080fd5b6153688c838d01614e0e565b909650945060608b013591508082111561538157600080fd5b506152948b828c01614e0e565b600080600080600060a086880312156153a657600080fd5b85356153b181614a02565b945060208601356153c181614a02565b9350604086013592506060860135915060808601356153df81614a02565b809150509295509295909350565b600181811c9082168061540157607f821691505b60208210810361542157634e487b7160e01b600052602260045260246000fd5b50919050565b60008154615434816153ed565b808552602060018381168015615451576001811461546b57615499565b60ff1985168884015283151560051b880183019550615499565b866000528260002060005b858110156154915781548a8201860152908301908401615476565b890184019650505b505050505092915050565b8054825260e0602083015260006154c160e0840160018401615427565b83810360408501526154d68160028501615427565b905083810360608501526154ed8160038501615427565b905083810360808501526155048160048501615427565b9050600583015460ff8116151560a086015261552a60c0860160ff8360081c1615159052565b509392505050565b60ff83168152604060208201526000610ed560408301846154a4565b60006020828403121561556057600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082028115828204841417610fd357610fd361557d565b634e487b7160e01b600052604160045260246000fd5b601f82111561185f57600081815260208120601f850160051c810160208610156155e75750805b601f850160051c820191505b81811015615606578281556001016155f3565b505050505050565b67ffffffffffffffff831115615626576156266155aa565b61563a8361563483546153ed565b836155c0565b6000601f84116001811461566e57600085156156565750838201355b600019600387901b1c1916600186901b178355611ca3565b600083815260209020601f19861690835b8281101561569f578685013582556020948501946001909201910161567f565b50868210156156bc5760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60006101208254845260018301546020850152600283015460408501526003830154606085015260048301546080850152600583015460a0850152600683015460c0850152615721600784015460ff1690565b151560e08501526101008401819052610ed581850160088501615427565b83815260ff83166020820152606060408201526000613bdb60608301846156ce565b6000600182016157735761577361557d565b5060010190565b60006020828403121561578c57600080fd5b8151614a9681614a27565b81810381811115610fd357610fd361557d565b80820180821115610fd357610fd361557d565b6000826157da57634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156157f157600080fd5b8151614a9681614a02565b602081526000614a9660208301846154a4565b634e487b7160e01b600052602160045260246000fd5b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b815167ffffffffffffffff81111561588a5761588a6155aa565b61589e8161589884546153ed565b846155c0565b602080601f8311600181146158d357600084156158bb5750858301515b600019600386901b1c1916600185901b178555615606565b600085815260208120601f198616915b82811015615902578886015182559484019460019091019084016158e3565b50858210156159205787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b828152604060208201526000610ed560408301846156ce56fe5fff5779f55d71041c8a8dac64fd1d4394cf4b41d7ef502baf7bbeabad381b37be670b8146f19d76b44fcaf05a819ec7dfe1d8265e48858e044fbed8126b0a23a2646970667358221220e6af59b87b4cc7646ac1b838eedb18bafe8df2c1b610dc63fc557a354bf136d064736f6c63430008110033

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

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.