ETH Price: $3,346.87 (-2.10%)

Token

XDEFI Badges (bXDEFI)
 

Overview

Max Total Supply

2,868 bXDEFI

Holders

1,421

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Balance
1 bXDEFI
0x168a7ed63aa0219365b174a94ac24384c8b53416
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
XDEFIDistribution

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2022-02-22
*/

// File: IEIP2612.sol



pragma solidity =0.8.12;

interface IEIP2612 {

    function permit(
        address owner_,
        address spender_,
        uint256 value_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external;

}

// File: @openzeppelin/contracts/token/ERC20/IERC20.sol


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

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

// File: @openzeppelin/contracts/utils/Strings.sol


// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

// File: @openzeppelin/contracts/utils/Context.sol


// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

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

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

// File: @openzeppelin/contracts/utils/Address.sol


// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [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://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/utils/introspection/IERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

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

// File: @openzeppelin/contracts/utils/introspection/ERC165.sol


// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;


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

// File: @openzeppelin/contracts/token/ERC721/IERC721.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;


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

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

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

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

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

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

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

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

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

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

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

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

// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)

pragma solidity ^0.8.0;


/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Enumerable is IERC721 {
    /**
     * @dev Returns the total amount of tokens stored by the contract.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
     * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);

    /**
     * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
     * Use along with {totalSupply} to enumerate all tokens.
     */
    function tokenByIndex(uint256 index) external view returns (uint256);
}

// File: IXDEFIDistribution.sol



pragma solidity =0.8.12;


interface IXDEFIDistribution is IERC721Enumerable {
    /***********/
    /* Structs */
    /***********/

    struct Position {
        uint96 units; // 240,000,000,000,000,000,000,000,000 XDEFI * 2.55x bonus (which fits in a `uint96`).
        uint88 depositedXDEFI; // XDEFI cap is 240000000000000000000000000 (which fits in a `uint88`).
        uint32 expiry; // block timestamps for the next 50 years (which fits in a `uint32`).
        uint32 created;
        uint256 pointsCorrection;
    }

    /**********/
    /* Errors */
    /**********/

    error BeyondConsumeLimit();
    error CannotUnlock();
    error ConsumePermitExpired();
    error EmptyArray();
    error IncorrectBonusMultiplier();
    error InsufficientAmountUnlocked();
    error InsufficientCredits();
    error InvalidConsumePermit();
    error InvalidDuration();
    error InvalidMultiplier();
    error InvalidToken();
    error LockingIsDisabled();
    error LockResultsInTooFewUnits();
    error MustMergeMultiple();
    error NoReentering();
    error NoUnitSupply();
    error NotApprovedOrOwnerOfToken();
    error NotInEmergencyMode();
    error PositionAlreadyUnlocked();
    error PositionStillLocked();
    error TokenDoesNotExist();
    error Unauthorized();

    /**********/
    /* Events */
    /**********/

    /// @notice Emitted when the base URI is set (or re-set).
    event BaseURISet(string baseURI);

    /// @notice Emitted when some credits of a token are consumed.
    event CreditsConsumed(uint256 indexed tokenId, address indexed consumer, uint256 amount);

    /// @notice Emitted when a new amount of XDEFI is distributed to all locked positions, by some caller.
    event DistributionUpdated(address indexed caller, uint256 amount);

    /// @notice Emitted when the contract is no longer allowing locking XDEFI, and is allowing all locked positions to be unlocked effective immediately.
    event EmergencyModeActivated();

    /// @notice Emitted when a new lock period duration, in seconds, has been enabled with some bonus multiplier (scaled by 100, 0 signaling it is disabled).
    event LockPeriodSet(uint256 indexed duration, uint256 indexed bonusMultiplier);

    /// @notice Emitted when a new locked position is created for some amount of XDEFI, and the NFT is minted to an owner.
    event LockPositionCreated(uint256 indexed tokenId, address indexed owner, uint256 amount, uint256 indexed duration);

    /// @notice Emitted when a locked position is unlocked, withdrawing some amount of XDEFI.
    event LockPositionWithdrawn(uint256 indexed tokenId, address indexed owner, uint256 amount);

    /// @notice Emitted when an account has accepted ownership.
    event OwnershipAccepted(address indexed previousOwner, address indexed owner);

    /// @notice Emitted when owner proposed an account that can accept ownership.
    event OwnershipProposed(address indexed owner, address indexed pendingOwner);

    /// @notice Emitted when unlocked tokens are merged into one.
    event TokensMerged(uint256[] mergedTokenIds, uint256 tokenId, uint256 credits);

    /*************/
    /* Constants */
    /*************/

    /// @notice The IERC721Permit domain separator.
    function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator_);

    /// @notice The minimum units that can result from a lock of XDEFI.
    function MINIMUM_UNITS() external view returns (uint256 minimumUnits_);

    /*********/
    /* State */
    /*********/

    /// @notice The base URI for NFT metadata.
    function baseURI() external view returns (string memory baseURI_);

    /// @notice The multiplier applied to the deposited XDEFI amount to determine the units of a position, and thus its share of future distributions.
    function bonusMultiplierOf(uint256 duration_) external view returns (uint256 bonusMultiplier_);

    /// @notice Returns the consume permit nonce for a token.
    function consumePermitNonce(uint256 tokenId_) external view returns (uint256 nonce_);

    /// @notice Returns the credits of a token.
    function creditsOf(uint256 tokenId_) external view returns (uint256 credits_);

    /// @notice The amount of XDEFI that is distributable to all currently locked positions.
    function distributableXDEFI() external view returns (uint256 distributableXDEFI_);

    /// @notice The contract is no longer allowing locking XDEFI, and is allowing all locked positions to be unlocked effective immediately.
    function inEmergencyMode() external view returns (bool lockingDisabled_);

    /// @notice The account that can set and unset lock periods and transfer ownership of the contract.
    function owner() external view returns (address owner_);

    /// @notice The account that can take ownership of the contract.
    function pendingOwner() external view returns (address pendingOwner_);

    /// @notice Returns the position details (`pointsCorrection_` is a value used in the amortized work pattern for token distribution).
    function positionOf(uint256 tokenId_) external view returns (Position memory position_);

    /// @notice The amount of XDEFI that was deposited by all currently locked positions.
    function totalDepositedXDEFI() external view returns (uint256 totalDepositedXDEFI_);

    /// @notice The amount of locked position units (in some way, it is the denominator use to distribute new XDEFI to each unit).
    function totalUnits() external view returns (uint256 totalUnits_);

    /// @notice The address of the XDEFI token.
    function xdefi() external view returns (address XDEFI_);

    /*******************/
    /* Admin Functions */
    /*******************/

    /// @notice Allows the `pendingOwner` to take ownership of the contract.
    function acceptOwnership() external;

    /// @notice Disallows locking XDEFI, and is allows all locked positions to be unlocked effective immediately.
    function activateEmergencyMode() external;

    /// @notice Allows the owner to propose a new owner for the contract.
    function proposeOwnership(address newOwner_) external;

    /// @notice Sets the base URI for NFT metadata.
    function setBaseURI(string calldata baseURI_) external;

    /// @notice Allows the setting or un-setting (when the multiplier is 0) of multipliers for lock durations. Scaled such that 1x is 100.
    function setLockPeriods(uint256[] calldata durations_, uint256[] calldata multipliers) external;

    /**********************/
    /* Position Functions */
    /**********************/

    /// @notice Unlock only the deposited amount from a non-fungible position, sending the XDEFI to some destination, when in emergency mode.
    function emergencyUnlock(uint256 tokenId_, address destination_) external returns (uint256 amountUnlocked_);

    /// @notice Returns the bonus multiplier of a locked position.
    function getBonusMultiplierOf(uint256 tokenId_) external view returns (uint256 bonusMultiplier_);

    /// @notice Locks some amount of XDEFI into a non-fungible (NFT) position, for a duration of time. The caller must first approve this contract to spend its XDEFI.
    function lock(
        uint256 amount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) external returns (uint256 tokenId_);

    /// @notice Locks some amount of XDEFI into a non-fungible (NFT) position, for a duration of time, with a signed permit to transfer XDEFI from the caller.
    function lockWithPermit(
        uint256 amount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external returns (uint256 tokenId_);

    /// @notice Unlock an un-lockable non-fungible position and re-lock some amount, for a duration of time, sending the balance XDEFI to some destination.
    function relock(
        uint256 tokenId_,
        uint256 lockAmount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) external returns (uint256 amountUnlocked_, uint256 newTokenId_);

    /// @notice Unlock an un-lockable non-fungible position, sending the XDEFI to some destination.
    function unlock(uint256 tokenId_, address destination_) external returns (uint256 amountUnlocked_);

    /// @notice To be called as part of distributions to force the contract to recognize recently transferred XDEFI as distributable.
    function updateDistribution() external;

    /// @notice Returns the amount of XDEFI that can be withdrawn when the position is unlocked. This will increase as distributions are made.
    function withdrawableOf(uint256 tokenId_) external view returns (uint256 withdrawableXDEFI_);

    /****************************/
    /* Batch Position Functions */
    /****************************/

    /// @notice Unlocks several un-lockable non-fungible positions and re-lock some amount, for a duration of time, sending the balance XDEFI to some destination.
    function relockBatch(
        uint256[] calldata tokenIds_,
        uint256 lockAmount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) external returns (uint256 amountUnlocked_, uint256 newTokenId_);

    /// @notice Unlocks several un-lockable non-fungible positions, sending the XDEFI to some destination.
    function unlockBatch(uint256[] calldata tokenIds_, address destination_) external returns (uint256 amountUnlocked_);

    /*****************/
    /* NFT Functions */
    /*****************/

    /// @notice Returns the tier and credits of an NFT.
    function attributesOf(uint256 tokenId_)
        external
        view
        returns (
            uint256 tier_,
            uint256 credits_,
            uint256 withdrawable_,
            uint256 expiry_
        );

    /// @notice Consumes some credits from an NFT, returning the number of credits left.
    function consume(uint256 tokenId_, uint256 amount_) external returns (uint256 remainingCredits_);

    /// @notice Consumes some credits from an NFT, with a signed permit from the owner, returning the number of credits left.
    function consumeWithPermit(
        uint256 tokenId_,
        uint256 amount_,
        uint256 limit_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external returns (uint256 remainingCredits_);

    /// @notice Returns the URI for the contract metadata.
    function contractURI() external view returns (string memory contractURI_);

    /// @notice Returns the credits an NFT will have, given some amount locked for some duration.
    function getCredits(uint256 amount_, uint256 duration_) external pure returns (uint256 credits_);

    /// @notice Returns the tier an NFT will have, given some credits, which itself can be determined from `getCredits`.
    function getTier(uint256 credits_) external pure returns (uint256 tier_);

    /// @notice Burns several unlocked NFTs to combine their credits into the first.
    function merge(uint256[] calldata tokenIds_) external returns (uint256 tokenId_, uint256 credits_);

    /// @notice Returns the URI for the NFT metadata for a given token ID.
    function tokenURI(uint256 tokenId_) external view returns (string memory tokenURI_);
}
// File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)

pragma solidity ^0.8.0;


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://eips.ethereum.org/EIPS/eip-721
 */
interface IERC721Metadata is IERC721 {
    /**
     * @dev Returns the token collection name.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the token collection symbol.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
     */
    function tokenURI(uint256 tokenId) external view returns (string memory);
}

// File: @openzeppelin/contracts/token/ERC721/ERC721.sol


// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/ERC721.sol)

pragma solidity ^0.8.0;








/**
 * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
 * the Metadata extension, but not including the Enumerable extension, which is available separately as
 * {ERC721Enumerable}.
 */
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
    using Address for address;
    using Strings for uint256;

    // Token name
    string private _name;

    // Token symbol
    string private _symbol;

    // Mapping from token ID to owner address
    mapping(uint256 => address) private _owners;

    // Mapping owner address to token count
    mapping(address => uint256) private _balances;

    // Mapping from token ID to approved address
    mapping(uint256 => address) private _tokenApprovals;

    // Mapping from owner to operator approvals
    mapping(address => mapping(address => bool)) private _operatorApprovals;

    /**
     * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC721).interfaceId ||
            interfaceId == type(IERC721Metadata).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721-balanceOf}.
     */
    function balanceOf(address owner) public view virtual override returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");
        return _balances[owner];
    }

    /**
     * @dev See {IERC721-ownerOf}.
     */
    function ownerOf(uint256 tokenId) public view virtual override returns (address) {
        address owner = _owners[tokenId];
        require(owner != address(0), "ERC721: owner query for nonexistent token");
        return owner;
    }

    /**
     * @dev See {IERC721Metadata-name}.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev See {IERC721Metadata-symbol}.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

    /**
     * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
     * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
     * by default, can be overriden in child contracts.
     */
    function _baseURI() internal view virtual returns (string memory) {
        return "";
    }

    /**
     * @dev See {IERC721-approve}.
     */
    function approve(address to, uint256 tokenId) public virtual override {
        address owner = ERC721.ownerOf(tokenId);
        require(to != owner, "ERC721: approval to current owner");

        require(
            _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _approve(to, tokenId);
    }

    /**
     * @dev See {IERC721-getApproved}.
     */
    function getApproved(uint256 tokenId) public view virtual override returns (address) {
        require(_exists(tokenId), "ERC721: approved query for nonexistent token");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev See {IERC721-setApprovalForAll}.
     */
    function setApprovalForAll(address operator, bool approved) public virtual override {
        _setApprovalForAll(_msgSender(), operator, approved);
    }

    /**
     * @dev See {IERC721-isApprovedForAll}.
     */
    function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev See {IERC721-transferFrom}.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");

        _transfer(from, to, tokenId);
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev See {IERC721-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) public virtual override {
        require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
        _safeTransfer(from, to, tokenId, _data);
    }

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * `_data` is additional data, it has no specified format and it is sent in call to `to`.
     *
     * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
     * implement alternative mechanisms to perform token transfer, such as signature-based.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeTransfer(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _transfer(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Returns whether `tokenId` exists.
     *
     * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
     *
     * Tokens start existing when they are minted (`_mint`),
     * and stop existing when they are burned (`_burn`).
     */
    function _exists(uint256 tokenId) internal view virtual returns (bool) {
        return _owners[tokenId] != address(0);
    }

    /**
     * @dev Returns whether `spender` is allowed to manage `tokenId`.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
        require(_exists(tokenId), "ERC721: operator query for nonexistent token");
        address owner = ERC721.ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Safely mints `tokenId` and transfers it to `to`.
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function _safeMint(address to, uint256 tokenId) internal virtual {
        _safeMint(to, tokenId, "");
    }

    /**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory _data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, _data),
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

    /**
     * @dev Mints `tokenId` and transfers it to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
     *
     * Requirements:
     *
     * - `tokenId` must not exist.
     * - `to` cannot be the zero address.
     *
     * Emits a {Transfer} event.
     */
    function _mint(address to, uint256 tokenId) internal virtual {
        require(to != address(0), "ERC721: mint to the zero address");
        require(!_exists(tokenId), "ERC721: token already minted");

        _beforeTokenTransfer(address(0), to, tokenId);

        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(address(0), to, tokenId);

        _afterTokenTransfer(address(0), to, tokenId);
    }

    /**
     * @dev Destroys `tokenId`.
     * The approval is cleared when the token is burned.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     *
     * Emits a {Transfer} event.
     */
    function _burn(uint256 tokenId) internal virtual {
        address owner = ERC721.ownerOf(tokenId);

        _beforeTokenTransfer(owner, address(0), tokenId);

        // Clear approvals
        _approve(address(0), tokenId);

        _balances[owner] -= 1;
        delete _owners[tokenId];

        emit Transfer(owner, address(0), tokenId);

        _afterTokenTransfer(owner, address(0), tokenId);
    }

    /**
     * @dev Transfers `tokenId` from `from` to `to`.
     *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     *
     * Emits a {Transfer} event.
     */
    function _transfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {
        require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
        require(to != address(0), "ERC721: transfer to the zero address");

        _beforeTokenTransfer(from, to, tokenId);

        // Clear approvals from the previous owner
        _approve(address(0), tokenId);

        _balances[from] -= 1;
        _balances[to] += 1;
        _owners[tokenId] = to;

        emit Transfer(from, to, tokenId);

        _afterTokenTransfer(from, to, tokenId);
    }

    /**
     * @dev Approve `to` to operate on `tokenId`
     *
     * Emits a {Approval} event.
     */
    function _approve(address to, uint256 tokenId) internal virtual {
        _tokenApprovals[tokenId] = to;
        emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
    }

    /**
     * @dev Approve `operator` to operate on all of `owner` tokens
     *
     * Emits a {ApprovalForAll} event.
     */
    function _setApprovalForAll(
        address owner,
        address operator,
        bool approved
    ) internal virtual {
        require(owner != operator, "ERC721: approve to caller");
        _operatorApprovals[owner][operator] = approved;
        emit ApprovalForAll(owner, operator, approved);
    }

    /**
     * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
     * The call is not executed if the target address is not a contract.
     *
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(
        address from,
        address to,
        uint256 tokenId,
        bytes memory _data
    ) private returns (bool) {
        if (to.isContract()) {
            try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
                return retval == IERC721Receiver.onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert("ERC721: transfer to non ERC721Receiver implementer");
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        } else {
            return true;
        }
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual {}
}

// File: @openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol


// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/ERC721Enumerable.sol)

pragma solidity ^0.8.0;



/**
 * @dev This implements an optional extension of {ERC721} defined in the EIP that adds
 * enumerability of all the token ids in the contract as well as all token ids owned by each
 * account.
 */
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
    // Mapping from owner to list of owned token IDs
    mapping(address => mapping(uint256 => uint256)) private _ownedTokens;

    // Mapping from token ID to index of the owner tokens list
    mapping(uint256 => uint256) private _ownedTokensIndex;

    // Array with all token ids, used for enumeration
    uint256[] private _allTokens;

    // Mapping from token id to position in the allTokens array
    mapping(uint256 => uint256) private _allTokensIndex;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
        return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
     */
    function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds");
        return _ownedTokens[owner][index];
    }

    /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _allTokens.length;
    }

    /**
     * @dev See {IERC721Enumerable-tokenByIndex}.
     */
    function tokenByIndex(uint256 index) public view virtual override returns (uint256) {
        require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds");
        return _allTokens[index];
    }

    /**
     * @dev Hook that is called before any token transfer. This includes minting
     * and burning.
     *
     * Calling conditions:
     *
     * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
     * transferred to `to`.
     * - When `from` is zero, `tokenId` will be minted for `to`.
     * - When `to` is zero, ``from``'s `tokenId` will be burned.
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal virtual override {
        super._beforeTokenTransfer(from, to, tokenId);

        if (from == address(0)) {
            _addTokenToAllTokensEnumeration(tokenId);
        } else if (from != to) {
            _removeTokenFromOwnerEnumeration(from, tokenId);
        }
        if (to == address(0)) {
            _removeTokenFromAllTokensEnumeration(tokenId);
        } else if (to != from) {
            _addTokenToOwnerEnumeration(to, tokenId);
        }
    }

    /**
     * @dev Private function to add a token to this extension's ownership-tracking data structures.
     * @param to address representing the new owner of the given token ID
     * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
     */
    function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
        uint256 length = ERC721.balanceOf(to);
        _ownedTokens[to][length] = tokenId;
        _ownedTokensIndex[tokenId] = length;
    }

    /**
     * @dev Private function to add a token to this extension's token tracking data structures.
     * @param tokenId uint256 ID of the token to be added to the tokens list
     */
    function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
        _allTokensIndex[tokenId] = _allTokens.length;
        _allTokens.push(tokenId);
    }

    /**
     * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
     * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
     * gas optimizations e.g. when performing a transfer operation (avoiding double writes).
     * This has O(1) time complexity, but alters the order of the _ownedTokens array.
     * @param from address representing the previous owner of the given token ID
     * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
     */
    function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
        // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = ERC721.balanceOf(from) - 1;
        uint256 tokenIndex = _ownedTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
        }

        // This also deletes the contents at the last position of the array
        delete _ownedTokensIndex[tokenId];
        delete _ownedTokens[from][lastTokenIndex];
    }

    /**
     * @dev Private function to remove a token from this extension's token tracking data structures.
     * This has O(1) time complexity, but alters the order of the _allTokens array.
     * @param tokenId uint256 ID of the token to be removed from the tokens list
     */
    function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
        // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
        // then delete the last slot (swap and pop).

        uint256 lastTokenIndex = _allTokens.length - 1;
        uint256 tokenIndex = _allTokensIndex[tokenId];

        // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
        // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
        // an 'if' statement (like in _removeTokenFromOwnerEnumeration)
        uint256 lastTokenId = _allTokens[lastTokenIndex];

        _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
        _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index

        // This also deletes the contents at the last position of the array
        delete _allTokensIndex[tokenId];
        _allTokens.pop();
    }
}

// File: XDEFIDistribution.sol



pragma solidity =0.8.12;





/// @dev Handles distributing XDEFI to NFTs that have locked up XDEFI for various durations of time.
contract XDEFIDistribution is IXDEFIDistribution, ERC721Enumerable {
    address internal constant ZERO_ADDRESS = address(0);

    uint256 internal constant ZERO_UINT256 = uint256(0);
    uint256 internal constant ONE_UINT256 = uint256(1);
    uint256 internal constant ONE_HUNDRED_UINT256 = uint256(100);

    uint256 internal constant TIER_1 = uint256(1);
    uint256 internal constant TIER_2 = uint256(2);
    uint256 internal constant TIER_3 = uint256(3);
    uint256 internal constant TIER_4 = uint256(4);
    uint256 internal constant TIER_5 = uint256(5);
    uint256 internal constant TIER_6 = uint256(6);
    uint256 internal constant TIER_7 = uint256(7);
    uint256 internal constant TIER_8 = uint256(8);
    uint256 internal constant TIER_9 = uint256(9);
    uint256 internal constant TIER_10 = uint256(10);
    uint256 internal constant TIER_11 = uint256(11);
    uint256 internal constant TIER_12 = uint256(12);
    uint256 internal constant TIER_13 = uint256(13);

    uint256 internal constant TIER_2_THRESHOLD = uint256(150 * 1e18 * 30 days);
    uint256 internal constant TIER_3_THRESHOLD = uint256(300 * 1e18 * 30 days);
    uint256 internal constant TIER_4_THRESHOLD = uint256(750 * 1e18 * 30 days);
    uint256 internal constant TIER_5_THRESHOLD = uint256(1_500 * 1e18 * 30 days);
    uint256 internal constant TIER_6_THRESHOLD = uint256(3_000 * 1e18 * 30 days);
    uint256 internal constant TIER_7_THRESHOLD = uint256(7_000 * 1e18 * 30 days);
    uint256 internal constant TIER_8_THRESHOLD = uint256(15_000 * 1e18 * 30 days);
    uint256 internal constant TIER_9_THRESHOLD = uint256(30_000 * 1e18 * 30 days);
    uint256 internal constant TIER_10_THRESHOLD = uint256(60_000 * 1e18 * 30 days);
    uint256 internal constant TIER_11_THRESHOLD = uint256(120_000 * 1e18 * 30 days);
    uint256 internal constant TIER_12_THRESHOLD = uint256(250_000 * 1e18 * 30 days);
    uint256 internal constant TIER_13_THRESHOLD = uint256(500_000 * 1e18 * 30 days);

    // See https://github.com/ethereum/EIPs/issues/1726#issuecomment-472352728
    uint256 internal constant POINTS_MULTIPLIER_BITS = uint256(72);
    uint256 internal _pointsPerUnit;

    address public immutable xdefi;

    uint256 public distributableXDEFI;
    uint256 public totalDepositedXDEFI;
    uint256 public totalUnits;

    mapping(uint256 => Position) internal _positionOf;

    mapping(uint256 => uint256) public creditsOf;

    mapping(uint256 => uint256) public bonusMultiplierOf; // Scaled by 100, capped at 255 (i.e. 1.1x is 110, 2.55x is 255).

    uint256 internal _tokensMinted;

    string public baseURI;

    address public owner;
    address public pendingOwner;

    uint256 internal constant IS_NOT_LOCKED = uint256(1);
    uint256 internal constant IS_LOCKED = uint256(2);

    uint256 internal _lockedStatus = IS_NOT_LOCKED;

    bool public inEmergencyMode;

    uint256 internal constant MAX_DURATION = uint256(315360000 seconds); // 10 years.
    uint256 internal constant MAX_BONUS_MULTIPLIER = uint256(255); // 2.55x.

    uint256 public constant MINIMUM_UNITS = uint256(1e18);

    bytes32 public immutable DOMAIN_SEPARATOR;

    mapping(uint256 => uint256) public consumePermitNonce;

    string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";

    // keccak256('PermitConsume(uint256 tokenId,address consumer,uint256 limit,uint256 nonce,uint256 deadline)');
    bytes32 private constant CONSUME_PERMIT_SIGNATURE_HASH = bytes32(0xa0a7128942405265cd830695cb06df90c6bfdbbe22677cc592c3d36c3180b079);

    constructor(address xdefi_, string memory baseURI_) ERC721("XDEFI Badges", "bXDEFI") {
        // Set `xdefi` immutable and check that it's not empty.
        if ((xdefi = xdefi_) == ZERO_ADDRESS) revert InvalidToken();

        owner = msg.sender;
        baseURI = baseURI_;

        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                // keccak256(bytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')),
                0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,
                // keccak256(bytes('XDEFI Badges')),
                0x4c62db20b6844e29b4686cc489ff0c3aac678cce88f9352a7a0ef17d53feb307,
                // keccak256(bytes('1')),
                0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6,
                block.chainid,
                address(this)
            )
        );
    }

    /*************/
    /* Modifiers */
    /*************/

    modifier onlyOwner() {
        if (owner != msg.sender) revert Unauthorized();

        _;
    }

    modifier noReenter() {
        if (_lockedStatus == IS_LOCKED) revert NoReentering();

        _lockedStatus = IS_LOCKED;
        _;
        _lockedStatus = IS_NOT_LOCKED;
    }

    modifier updatePointsPerUnitAtStart() {
        updateDistribution();
        _;
    }

    modifier updateDistributableAtEnd() {
        _;
        // NOTE: This needs to be done after updating `totalDepositedXDEFI` (which happens in `_destroyLockedPosition`) and transferring out.
        _updateDistributableXDEFI();
    }

    /*******************/
    /* Admin Functions */
    /*******************/

    function acceptOwnership() external {
        if (pendingOwner != msg.sender) revert Unauthorized();

        emit OwnershipAccepted(owner, msg.sender);
        owner = msg.sender;
        pendingOwner = ZERO_ADDRESS;
    }

    function activateEmergencyMode() external onlyOwner {
        inEmergencyMode = true;
        emit EmergencyModeActivated();
    }

    function proposeOwnership(address newOwner_) external onlyOwner {
        emit OwnershipProposed(owner, pendingOwner = newOwner_);
    }

    function setBaseURI(string calldata baseURI_) external onlyOwner {
        emit BaseURISet(baseURI = baseURI_);
    }

    function setLockPeriods(uint256[] calldata durations_, uint256[] calldata multipliers_) external onlyOwner {
        // Revert if an empty duration array is passed in, which would result in a successful, yet wasted useless transaction.
        if (durations_.length == ZERO_UINT256) revert EmptyArray();

        for (uint256 i; i < durations_.length; ) {
            uint256 duration = durations_[i];
            uint256 multiplier = multipliers_[i];

            // Revert if duration is 0 or longer than max defined.
            if (duration == ZERO_UINT256 || duration > MAX_DURATION) revert InvalidDuration();

            // Revert if bonus multiplier is larger than max defined.
            if (multiplier > MAX_BONUS_MULTIPLIER) revert InvalidMultiplier();

            emit LockPeriodSet(duration, bonusMultiplierOf[duration] = multiplier);

            unchecked {
                ++i;
            }
        }
    }

    /**********************/
    /* Position Functions */
    /**********************/

    function emergencyUnlock(uint256 tokenId_, address destination_) external noReenter updateDistributableAtEnd returns (uint256 amountUnlocked_) {
        // Revert if not in emergency mode.
        if (!inEmergencyMode) revert NotInEmergencyMode();

        // Revert if caller is not the token's owner, not approved for all the owner's token, and not approved for this specific token.
        if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert NotApprovedOrOwnerOfToken();

        // Fetch position.
        Position storage position = _positionOf[tokenId_];
        uint256 units = uint256(position.units);
        amountUnlocked_ = uint256(position.depositedXDEFI);

        // Track deposits.
        // NOTE: Can be unchecked since `totalDepositedXDEFI` increase in `_createLockedPosition` is the only place where `totalDepositedXDEFI` is set.
        unchecked {
            totalDepositedXDEFI -= amountUnlocked_;
        }

        // Delete FDT Position.
        // NOTE: Can be unchecked since `totalUnits` increase in `_createLockedPosition` is the only place where `totalUnits` is set.
        unchecked {
            totalUnits -= units;
        }

        delete _positionOf[tokenId_];

        // Send the unlocked XDEFI to the destination. (Don't need SafeERC20 since XDEFI is standard ERC20).
        IERC20(xdefi).transfer(destination_, amountUnlocked_);
    }

    function getBonusMultiplierOf(uint256 tokenId_) external view returns (uint256 bonusMultiplier_) {
        // Fetch position.
        Position storage position = _positionOf[tokenId_];
        uint256 units = uint256(position.units);
        uint256 depositedXDEFI = uint256(position.depositedXDEFI);

        bonusMultiplier_ = (units * ONE_HUNDRED_UINT256) / depositedXDEFI;
    }

    function lock(
        uint256 amount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) external noReenter updatePointsPerUnitAtStart returns (uint256 tokenId_) {
        tokenId_ = _lock(amount_, duration_, bonusMultiplier_, destination_);
    }

    function lockWithPermit(
        uint256 amount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external noReenter updatePointsPerUnitAtStart returns (uint256 tokenId_) {
        // Approve this contract for the amount, using the provided signature.
        IEIP2612(xdefi).permit(msg.sender, address(this), amount_, deadline_, v_, r_, s_);

        tokenId_ = _lock(amount_, duration_, bonusMultiplier_, destination_);
    }

    function positionOf(uint256 tokenId_) external view returns (Position memory position_) {
        position_ = _positionOf[tokenId_];
    }

    function relock(
        uint256 tokenId_,
        uint256 lockAmount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) external noReenter updatePointsPerUnitAtStart updateDistributableAtEnd returns (uint256 amountUnlocked_, uint256 newTokenId_) {
        // Handle the unlock and get the amount of XDEFI eligible to withdraw.
        amountUnlocked_ = _destroyLockedPosition(msg.sender, tokenId_);

        newTokenId_ = _relock(lockAmount_, amountUnlocked_, duration_, bonusMultiplier_, destination_);
    }

    function unlock(uint256 tokenId_, address destination_) external noReenter updatePointsPerUnitAtStart updateDistributableAtEnd returns (uint256 amountUnlocked_) {
        // Handle the unlock and get the amount of XDEFI eligible to withdraw.
        amountUnlocked_ = _destroyLockedPosition(msg.sender, tokenId_);

        // Send the unlocked XDEFI to the destination. (Don't need SafeERC20 since XDEFI is standard ERC20).
        IERC20(xdefi).transfer(destination_, amountUnlocked_);
    }

    function updateDistribution() public {
        // NOTE: Since `_updateDistributableXDEFI` is called anywhere after XDEFI is withdrawn from the contract, here `changeInDistributableXDEFI` should always be greater than 0.
        uint256 increaseInDistributableXDEFI = _updateDistributableXDEFI();

        // Return if no change in distributable XDEFI.
        if (increaseInDistributableXDEFI == ZERO_UINT256) return;

        uint256 totalUnitsCached = totalUnits;

        // Revert if `totalUnitsCached` is zero. (This would have reverted anyway in the line below.)
        if (totalUnitsCached == ZERO_UINT256) revert NoUnitSupply();

        // NOTE: Max numerator is 240_000_000 * 1e18 * (2 ** 72), which is less than `type(uint256).max`, and min denominator is 1.
        //       So, `_pointsPerUnit` can grow by 2**160 every distribution of XDEFI's max supply.
        unchecked {
            _pointsPerUnit += (increaseInDistributableXDEFI << POINTS_MULTIPLIER_BITS) / totalUnitsCached;
        }

        emit DistributionUpdated(msg.sender, increaseInDistributableXDEFI);
    }

    function withdrawableOf(uint256 tokenId_) public view returns (uint256 withdrawableXDEFI_) {
        Position storage position = _positionOf[tokenId_];
        withdrawableXDEFI_ = _withdrawableGiven(position.units, position.depositedXDEFI, position.pointsCorrection);
    }

    /****************************/
    /* Batch Position Functions */
    /****************************/

    function relockBatch(
        uint256[] calldata tokenIds_,
        uint256 lockAmount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) external noReenter updatePointsPerUnitAtStart updateDistributableAtEnd returns (uint256 amountUnlocked_, uint256 newTokenId_) {
        // Handle the unlocks and get the amount of XDEFI eligible to withdraw.
        amountUnlocked_ = _unlockBatch(msg.sender, tokenIds_);

        newTokenId_ = _relock(lockAmount_, amountUnlocked_, duration_, bonusMultiplier_, destination_);
    }

    function unlockBatch(uint256[] calldata tokenIds_, address destination_) external noReenter updatePointsPerUnitAtStart updateDistributableAtEnd returns (uint256 amountUnlocked_) {
        // Handle the unlocks and get the amount of XDEFI eligible to withdraw.
        amountUnlocked_ = _unlockBatch(msg.sender, tokenIds_);

        // Send the unlocked XDEFI to the destination. (Don't need SafeERC20 since XDEFI is standard ERC20).
        IERC20(xdefi).transfer(destination_, amountUnlocked_);
    }

    /*****************/
    /* NFT Functions */
    /*****************/

    function attributesOf(uint256 tokenId_)
        external
        view
        returns (
            uint256 tier_,
            uint256 credits_,
            uint256 withdrawable_,
            uint256 expiry_
        )
    {
        // Revert if the token does not exist.
        if (!_exists(tokenId_)) revert TokenDoesNotExist();

        credits_ = creditsOf[tokenId_];
        tier_ = getTier(credits_);
        withdrawable_ = withdrawableOf(tokenId_);
        expiry_ = _positionOf[tokenId_].expiry;
    }

    function consume(uint256 tokenId_, uint256 amount_) external returns (uint256 remainingCredits_) {
        // Revert if the caller is not the token's owner, not approved for all the owner's token, and not approved for this specific token.
        if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert InvalidConsumePermit();

        // Consume some of the token's credits.
        remainingCredits_ = _consume(tokenId_, amount_, msg.sender);
    }

    function consumeWithPermit(
        uint256 tokenId_,
        uint256 amount_,
        uint256 limit_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external returns (uint256 remainingCredits_) {
        // Revert if the permit's deadline has been elapsed.
        if (block.timestamp >= deadline_) revert ConsumePermitExpired();

        // Revert if the amount being consumed is greater than the permit's defined limit.
        if (amount_ > limit_) revert BeyondConsumeLimit();

        // Hash the data as per keccak256("PermitConsume(uint256 tokenId,address consumer,uint256 limit,uint256 nonce,uint256 deadline)");
        bytes32 digest = keccak256(abi.encode(CONSUME_PERMIT_SIGNATURE_HASH, tokenId_, msg.sender, limit_, consumePermitNonce[tokenId_]++, deadline_));

        // Get the digest that was to be signed signed.
        digest = keccak256(abi.encodePacked(EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA, DOMAIN_SEPARATOR, digest));

        address recoveredAddress = ecrecover(digest, v_, r_, s_);

        // Revert if the account that signed the permit is not the token's owner, not approved for all the owner's token, and not approved for this specific token.
        if (!_isApprovedOrOwner(recoveredAddress, tokenId_)) revert InvalidConsumePermit();

        // Consume some of the token's credits.
        remainingCredits_ = _consume(tokenId_, amount_, msg.sender);
    }

    function contractURI() external view returns (string memory contractURI_) {
        contractURI_ = string(abi.encodePacked(baseURI, "info"));
    }

    function getCredits(uint256 amount_, uint256 duration_) public pure returns (uint256 credits_) {
        // Credits is implicitly capped at max supply of XDEFI for 10 years locked (less than 2**116).
        unchecked {
            credits_ = amount_ * duration_;
        }
    }

    function getTier(uint256 credits_) public pure returns (uint256 tier_) {
        if (credits_ < TIER_2_THRESHOLD) return TIER_1;

        if (credits_ < TIER_3_THRESHOLD) return TIER_2;

        if (credits_ < TIER_4_THRESHOLD) return TIER_3;

        if (credits_ < TIER_5_THRESHOLD) return TIER_4;

        if (credits_ < TIER_6_THRESHOLD) return TIER_5;

        if (credits_ < TIER_7_THRESHOLD) return TIER_6;

        if (credits_ < TIER_8_THRESHOLD) return TIER_7;

        if (credits_ < TIER_9_THRESHOLD) return TIER_8;

        if (credits_ < TIER_10_THRESHOLD) return TIER_9;

        if (credits_ < TIER_11_THRESHOLD) return TIER_10;

        if (credits_ < TIER_12_THRESHOLD) return TIER_11;

        if (credits_ < TIER_13_THRESHOLD) return TIER_12;

        return TIER_13;
    }

    function merge(uint256[] calldata tokenIds_) external returns (uint256 tokenId_, uint256 credits_) {
        // Revert if trying to merge 0 or 1 tokens, which cannot be done.
        if (tokenIds_.length <= ONE_UINT256) revert MustMergeMultiple();

        uint256 iterator = tokenIds_.length - 1;

        // For each NFT from last to second, check that it belongs to the caller, burn it, and accumulate the credits.
        while (iterator > ZERO_UINT256) {
            tokenId_ = tokenIds_[iterator];

            // Revert if the caller is not the token's owner, not approved for all the owner's token, and not approved for this specific token.
            if (!_isApprovedOrOwner(msg.sender, tokenId_)) revert NotApprovedOrOwnerOfToken();

            // Revert if position has an expiry property, which means it still exists.
            if (_positionOf[tokenId_].expiry != ZERO_UINT256) revert PositionStillLocked();

            unchecked {
                // Max credits of a previously locked position is `type(uint128).max`, so `credits_` is reasonably not going to overflow.
                credits_ += creditsOf[tokenId_];

                --iterator;
            }

            // Clear the credits for this token, and burn the token.
            delete creditsOf[tokenId_];
            _burn(tokenId_);
        }

        // The resulting token id is the first token.
        tokenId_ = tokenIds_[0];

        // The total credits merged into the first token is the sum of the first's plus the accumulation of the credits from burned tokens.
        credits_ = (creditsOf[tokenId_] += credits_);

        emit TokensMerged(tokenIds_, tokenId_, credits_);
    }

    function tokenURI(uint256 tokenId_) public view override(IXDEFIDistribution, ERC721) returns (string memory tokenURI_) {
        // Revert if the token does not exist.
        if (!_exists(tokenId_)) revert TokenDoesNotExist();

        tokenURI_ = string(abi.encodePacked(baseURI, Strings.toString(tokenId_)));
    }

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

    function _consume(
        uint256 tokenId_,
        uint256 amount_,
        address consumer_
    ) internal returns (uint256 remainingCredits_) {
        remainingCredits_ = creditsOf[tokenId_];

        // Revert if credits to decrement is greater than credits of nft.
        if (amount_ > remainingCredits_) revert InsufficientCredits();

        unchecked {
            // Can be unchecked due to check done above.
            creditsOf[tokenId_] = (remainingCredits_ -= amount_);
        }

        emit CreditsConsumed(tokenId_, consumer_, amount_);
    }

    function _createLockedPosition(
        uint256 amount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) internal returns (uint256 tokenId_) {
        // Revert is locking has been disabled.
        if (inEmergencyMode) revert LockingIsDisabled();

        uint256 bonusMultiplier = bonusMultiplierOf[duration_];

        // Revert if the bonus multiplier is zero.
        if (bonusMultiplier == ZERO_UINT256) revert InvalidDuration();

        // Revert if the bonus multiplier is not at least what was expected.
        if (bonusMultiplier < bonusMultiplier_) revert IncorrectBonusMultiplier();

        unchecked {
            // Generate a token id.
            tokenId_ = ++_tokensMinted;

            // Store credits.
            creditsOf[tokenId_] = getCredits(amount_, duration_);

            // Track deposits.
            totalDepositedXDEFI += amount_;

            // The rest creates the locked position.
            uint256 units = (amount_ * bonusMultiplier) / ONE_HUNDRED_UINT256;

            // Revert if position will end up with less than define minimum lockable units.
            if (units < MINIMUM_UNITS) revert LockResultsInTooFewUnits();

            totalUnits += units;

            _positionOf[tokenId_] = Position({
                units: uint96(units), // 240M * 1e18 * 255 can never be larger than a `uint96`.
                depositedXDEFI: uint88(amount_), // There are only 240M (18 decimals) XDEFI tokens so can never be larger than a `uint88`.
                expiry: uint32(block.timestamp + duration_), // For many years, block.timestamp + duration_ will never be larger than a `uint32`.
                created: uint32(block.timestamp), // For many years, block.timestamp will never be larger than a `uint32`.
                pointsCorrection: _pointsPerUnit * units // _pointsPerUnit * units cannot be greater than a `uint256`.
            });
        }

        emit LockPositionCreated(tokenId_, destination_, amount_, duration_);

        // Mint a locked staked position NFT to the destination.
        _safeMint(destination_, tokenId_);
    }

    function _destroyLockedPosition(address account_, uint256 tokenId_) internal returns (uint256 amountUnlocked_) {
        // Revert if account_ is not the token's owner, not approved for all the owner's token, and not approved for this specific token.
        if (!_isApprovedOrOwner(account_, tokenId_)) revert NotApprovedOrOwnerOfToken();

        // Fetch position.
        Position storage position = _positionOf[tokenId_];
        uint256 units = uint256(position.units);
        uint256 depositedXDEFI = uint256(position.depositedXDEFI);
        uint256 expiry = uint256(position.expiry);

        // Revert if the position does not have an expiry, which means the position does not exist.
        if (expiry == ZERO_UINT256) revert PositionAlreadyUnlocked();

        // Revert if not enough time has elapsed in order to unlock AND locking is not disabled (which would mean we are allowing emergency withdrawals).
        if (block.timestamp < expiry && !inEmergencyMode) revert CannotUnlock();

        // Get the withdrawable amount of XDEFI for the position.
        amountUnlocked_ = _withdrawableGiven(units, depositedXDEFI, position.pointsCorrection);

        // Track deposits.
        // NOTE: Can be unchecked since `totalDepositedXDEFI` increase in `_createLockedPosition` is the only place where `totalDepositedXDEFI` is set.
        unchecked {
            totalDepositedXDEFI -= depositedXDEFI;
        }

        // Delete FDT Position.
        // NOTE: Can be unchecked since `totalUnits` increase in `_createLockedPosition` is the only place where `totalUnits` is set.
        unchecked {
            totalUnits -= units;
        }

        delete _positionOf[tokenId_];

        emit LockPositionWithdrawn(tokenId_, account_, amountUnlocked_);
    }

    function _lock(
        uint256 amount_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) internal returns (uint256 tokenId_) {
        // Lock the XDEFI in the contract. (Don't need SafeERC20 since XDEFI is standard ERC20).
        IERC20(xdefi).transferFrom(msg.sender, address(this), amount_);

        // Handle the lock position creation and get the tokenId of the locked position.
        tokenId_ = _createLockedPosition(amount_, duration_, bonusMultiplier_, destination_);
    }

    function _relock(
        uint256 lockAmount_,
        uint256 amountUnlocked_,
        uint256 duration_,
        uint256 bonusMultiplier_,
        address destination_
    ) internal returns (uint256 tokenId_) {
        // Throw convenient error if trying to re-lock more than was unlocked. `amountUnlocked_ - lockAmount_` cannot revert below now.
        if (lockAmount_ > amountUnlocked_) revert InsufficientAmountUnlocked();

        // Handle the lock position creation and get the tokenId of the locked position.
        tokenId_ = _createLockedPosition(lockAmount_, duration_, bonusMultiplier_, destination_);

        unchecked {
            if (amountUnlocked_ - lockAmount_ != ZERO_UINT256) {
                // Send the excess XDEFI to the destination, if needed. (Don't need SafeERC20 since XDEFI is standard ERC20).
                IERC20(xdefi).transfer(destination_, amountUnlocked_ - lockAmount_);
            }
        }
    }

    function _unlockBatch(address account_, uint256[] calldata tokenIds_) internal returns (uint256 amountUnlocked_) {
        // Revert if trying to unlock 0 positions, which would result in a successful, yet wasted useless transaction.
        if (tokenIds_.length == ZERO_UINT256) revert EmptyArray();

        // Handle the unlock for each position and accumulate the unlocked amount.
        for (uint256 i; i < tokenIds_.length; ) {
            unchecked {
                amountUnlocked_ += _destroyLockedPosition(account_, tokenIds_[i]);

                ++i;
            }
        }
    }

    function _updateDistributableXDEFI() internal returns (uint256 increaseInDistributableXDEFI_) {
        uint256 xdefiBalance = IERC20(xdefi).balanceOf(address(this));
        uint256 previousDistributableXDEFI = distributableXDEFI;

        unchecked {
            uint256 currentDistributableXDEFI = xdefiBalance > totalDepositedXDEFI ? xdefiBalance - totalDepositedXDEFI : ZERO_UINT256;

            // Return 0 early if distributable XDEFI did not change.
            if (currentDistributableXDEFI == previousDistributableXDEFI) return ZERO_UINT256;

            // Set distributableXDEFI.
            distributableXDEFI = currentDistributableXDEFI;

            // Return 0 early if distributable XDEFI decreased.
            if (currentDistributableXDEFI < previousDistributableXDEFI) return ZERO_UINT256;

            increaseInDistributableXDEFI_ = currentDistributableXDEFI - previousDistributableXDEFI;
        }
    }

    function _withdrawableGiven(
        uint256 units_,
        uint256 depositedXDEFI_,
        uint256 pointsCorrection_
    ) internal view returns (uint256 withdrawableXDEFI_) {
        // NOTE: In a worst case (120k XDEFI locked at 2.55x bonus, 120k XDEFI reward, cycled 1 million times) `_pointsPerUnit * units_` is smaller than 2**248.
        //       Since `pointsCorrection_` is always less than `_pointsPerUnit * units_`, (because `_pointsPerUnit` only grows) there is no underflow on the subtraction.
        //       Finally, `depositedXDEFI_` is at most 88 bits, so after the division by a very large `POINTS_MULTIPLIER`, this doesn't need to be checked.
        unchecked {
            withdrawableXDEFI_ = (((_pointsPerUnit * units_) - pointsCorrection_) >> POINTS_MULTIPLIER_BITS) + depositedXDEFI_;
        }
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"xdefi_","type":"address"},{"internalType":"string","name":"baseURI_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BeyondConsumeLimit","type":"error"},{"inputs":[],"name":"CannotUnlock","type":"error"},{"inputs":[],"name":"ConsumePermitExpired","type":"error"},{"inputs":[],"name":"EmptyArray","type":"error"},{"inputs":[],"name":"IncorrectBonusMultiplier","type":"error"},{"inputs":[],"name":"InsufficientAmountUnlocked","type":"error"},{"inputs":[],"name":"InsufficientCredits","type":"error"},{"inputs":[],"name":"InvalidConsumePermit","type":"error"},{"inputs":[],"name":"InvalidDuration","type":"error"},{"inputs":[],"name":"InvalidMultiplier","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"LockResultsInTooFewUnits","type":"error"},{"inputs":[],"name":"LockingIsDisabled","type":"error"},{"inputs":[],"name":"MustMergeMultiple","type":"error"},{"inputs":[],"name":"NoReentering","type":"error"},{"inputs":[],"name":"NoUnitSupply","type":"error"},{"inputs":[],"name":"NotApprovedOrOwnerOfToken","type":"error"},{"inputs":[],"name":"NotInEmergencyMode","type":"error"},{"inputs":[],"name":"PositionAlreadyUnlocked","type":"error"},{"inputs":[],"name":"PositionStillLocked","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"consumer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"CreditsConsumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DistributionUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyModeActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"bonusMultiplier","type":"uint256"}],"name":"LockPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"duration","type":"uint256"}],"name":"LockPositionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LockPositionWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"OwnershipAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"mergedTokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"credits","type":"uint256"}],"name":"TokensMerged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_UNITS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activateEmergencyMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"attributesOf","outputs":[{"internalType":"uint256","name":"tier_","type":"uint256"},{"internalType":"uint256","name":"credits_","type":"uint256"},{"internalType":"uint256","name":"withdrawable_","type":"uint256"},{"internalType":"uint256","name":"expiry_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"bonusMultiplierOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"consume","outputs":[{"internalType":"uint256","name":"remainingCredits_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"consumePermitNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"limit_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"consumeWithPermit","outputs":[{"internalType":"uint256","name":"remainingCredits_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"contractURI_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"creditsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"distributableXDEFI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"emergencyUnlock","outputs":[{"internalType":"uint256","name":"amountUnlocked_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"getBonusMultiplierOf","outputs":[{"internalType":"uint256","name":"bonusMultiplier_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"}],"name":"getCredits","outputs":[{"internalType":"uint256","name":"credits_","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"credits_","type":"uint256"}],"name":"getTier","outputs":[{"internalType":"uint256","name":"tier_","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"inEmergencyMode","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"},{"internalType":"uint256","name":"bonusMultiplier_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"lock","outputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"},{"internalType":"uint256","name":"bonusMultiplier_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"lockWithPermit","outputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"}],"name":"merge","outputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"credits_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"positionOf","outputs":[{"components":[{"internalType":"uint96","name":"units","type":"uint96"},{"internalType":"uint88","name":"depositedXDEFI","type":"uint88"},{"internalType":"uint32","name":"expiry","type":"uint32"},{"internalType":"uint32","name":"created","type":"uint32"},{"internalType":"uint256","name":"pointsCorrection","type":"uint256"}],"internalType":"struct IXDEFIDistribution.Position","name":"position_","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner_","type":"address"}],"name":"proposeOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"lockAmount_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"},{"internalType":"uint256","name":"bonusMultiplier_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"relock","outputs":[{"internalType":"uint256","name":"amountUnlocked_","type":"uint256"},{"internalType":"uint256","name":"newTokenId_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"uint256","name":"lockAmount_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"},{"internalType":"uint256","name":"bonusMultiplier_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"relockBatch","outputs":[{"internalType":"uint256","name":"amountUnlocked_","type":"uint256"},{"internalType":"uint256","name":"newTokenId_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"durations_","type":"uint256[]"},{"internalType":"uint256[]","name":"multipliers_","type":"uint256[]"}],"name":"setLockPeriods","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"tokenURI_","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDepositedXDEFI","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"unlock","outputs":[{"internalType":"uint256","name":"amountUnlocked_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds_","type":"uint256[]"},{"internalType":"address","name":"destination_","type":"address"}],"name":"unlockBatch","outputs":[{"internalType":"uint256","name":"amountUnlocked_","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"withdrawableOf","outputs":[{"internalType":"uint256","name":"withdrawableXDEFI_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xdefi","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c060405260016015553480156200001657600080fd5b5060405162003e4f38038062003e4f833981016040819052620000399162000260565b604080518082018252600c81526b58444546492042616467657360a01b60208083019182528351808501909452600684526562584445464960d01b9084015281519192916200008b91600091620001a4565b508051620000a1906001906020840190620001a4565b5050506001600160a01b0382166080819052620000d15760405163c1ab6dc160e01b815260040160405180910390fd5b601380546001600160a01b031916331790558051620000f8906012906020840190620001a4565b50604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f4c62db20b6844e29b4686cc489ff0c3aac678cce88f9352a7a0ef17d53feb307918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160408051601f19818403018152919052805160209091012060a052506200039d9050565b828054620001b29062000360565b90600052602060002090601f016020900481019282620001d6576000855562000221565b82601f10620001f157805160ff191683800117855562000221565b8280016001018555821562000221579182015b828111156200022157825182559160200191906001019062000204565b506200022f92915062000233565b5090565b5b808211156200022f576000815560010162000234565b634e487b7160e01b600052604160045260246000fd5b600080604083850312156200027457600080fd5b82516001600160a01b03811681146200028c57600080fd5b602084810151919350906001600160401b0380821115620002ac57600080fd5b818601915086601f830112620002c157600080fd5b815181811115620002d657620002d66200024a565b604051601f8201601f19908116603f011681019083821181831017156200030157620003016200024a565b8160405282815289868487010111156200031a57600080fd5b600093505b828410156200033e57848401860151818501870152928501926200031f565b82841115620003505760008684830101525b8096505050505050509250929050565b600181811c908216806200037557607f821691505b602082108114156200039757634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a051613a54620003fb600039600081816104ab0152610e040152600081816103dd01528181610bf2015281816110400152818161136301528181611d1001528181612167015281816122de01526123bf0152613a546000f3fe608060405234801561001057600080fd5b506004361061030c5760003560e01c80636c0360eb1161019d578063b7739ce1116100e9578063d3646e79116100a2578063e30c39781161007c578063e30c3978146107f2578063e8a3d48514610805578063e985e9c51461080d578063f1d2ec1d1461084957600080fd5b8063d3646e79146107ac578063d983103d146107cc578063de62d842146107df57600080fd5b8063b7739ce11461074c578063b88d4fde1461075e578063bd3a1adb14610771578063c87b56dd1461077e578063d009601014610791578063d1fdb3e81461079957600080fd5b80638ca31af911610156578063986419c711610130578063986419c714610715578063a22cb46514610728578063a83d4dda1461073b578063aa8badc11461074457600080fd5b80638ca31af9146106d25780638da5cb5b146106fa57806395d89b411461070d57600080fd5b80636c0360eb146106805780636d86acc41461068857806370a0823114610691578063710bf322146106a457806379ba5097146106b75780637f082d22146106bf57600080fd5b806330be763e1161025c5780634eeea7ad1161021557806350da4ed7116101ef57806350da4ed71461063857806355f804b31461064b578063579d13b81461065e5780636352211e1461066d57600080fd5b80634eeea7ad146105ff5780634f062c5a146106125780634f6ccce71461062557600080fd5b806330be763e1461048057806335b2b215146104935780633644e515146104a657806342842e0e146104cd57806346f96023146104e05780634db1bb96146105ec57600080fd5b80630fed817f116102c957806323b872dd116102a357806323b872dd146104275780632f588cd41461043a5780632f745c591461044d578063306536bd1461046057600080fd5b80630fed817f146103d857806318160ddd146103ff5780631c5898091461040757600080fd5b806301ffc9a71461031157806306fdde0314610339578063074737421461034e578063081812fc1461036557806309363c4414610390578063095ea7b3146103c3575b600080fd5b61032461031f366004612fa0565b61085c565b60405190151581526020015b60405180910390f35b610341610887565b6040516103309190613015565b610357600c5481565b604051908152602001610330565b610378610373366004613028565b610919565b6040516001600160a01b039091168152602001610330565b6103a361039e366004613028565b6109b3565b604080519485526020850193909352918301526060820152608001610330565b6103d66103d136600461305d565b610a44565b005b6103787f000000000000000000000000000000000000000000000000000000000000000081565b600854610357565b610357610415366004613028565b600f6020526000908152604090205481565b6103d6610435366004613087565b610b5a565b61035761044836600461310f565b610b8b565b61035761045b36600461305d565b610c77565b61035761046e366004613028565b60176020526000908152604090205481565b61035761048e366004613174565b610d0d565b6103576104a13660046131d0565b610ee3565b6103577f000000000000000000000000000000000000000000000000000000000000000081565b6103d66104db366004613087565b610f30565b61058c6104ee366004613028565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506000908152600e6020908152604091829020825160a08101845281546001600160601b03811682526001600160581b03600160601b8204169382019390935263ffffffff600160b81b8404811694820194909452600160d81b9092049092166060820152600190910154608082015290565b6040516103309190600060a0820190506001600160601b0383511682526001600160581b036020840151166020830152604083015163ffffffff808216604085015280606086015116606085015250506080830151608083015292915050565b6103576105fa36600461320f565b610f4b565b61035761060d36600461323b565b6110c4565b610357610620366004613028565b6110ff565b610357610633366004613028565b61125d565b61035761064636600461325d565b6112f0565b6103d66106593660046132ca565b6113e5565b610357670de0b6b3a764000081565b61037861067b366004613028565b611455565b6103416114cc565b610357600d5481565b61035761069f36600461333c565b61155a565b6103d66106b236600461333c565b6115e1565b6103d661165d565b6103576106cd366004613028565b6116df565b6106e56106e0366004613357565b611729565b60408051928352602083019190915201610330565b601354610378906001600160a01b031681565b610341611794565b6103d66107233660046133c6565b6117a3565b6103d6610736366004613440565b6118ce565b610357600b5481565b6103d66118dd565b61035761075a36600461323b565b0290565b6103d661076c36600461348d565b61196b565b6016546103249060ff1681565b61034161078c366004613028565b6119a3565b6103d6611a0d565b6103576107a7366004613028565b611a6f565b6103576107ba366004613028565b60106020526000908152604090205481565b6106e56107da366004613569565b611aad565b6106e56107ed3660046135b2565b611b16565b601454610378906001600160a01b031681565b610341611c82565b61032461081b3660046135f4565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61035761085736600461320f565b611caa565b60006001600160e01b0319821663780e9d6360e01b1480610881575061088182611d88565b92915050565b6060600080546108969061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546108c29061361e565b801561090f5780601f106108e45761010080835404028352916020019161090f565b820191906000526020600020905b8154815290600101906020018083116108f257829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b03166109975760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000806000806109da856000908152600260205260409020546001600160a01b0316151590565b6109f75760405163677510db60e11b815260040160405180910390fd5b6000858152600f60205260409020549250610a11836110ff565b9350610a1c85611a6f565b6000958652600e6020526040909520549395929493600160b81b900463ffffffff1692915050565b6000610a4f82611455565b9050806001600160a01b0316836001600160a01b03161415610abd5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161098e565b336001600160a01b0382161480610ad95750610ad9813361081b565b610b4b5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000606482015260840161098e565b610b558383611dd8565b505050565b610b643382611e46565b610b805760405162461bcd60e51b815260040161098e90613659565b610b55838383611f3d565b600060026015541415610bb15760405163cbece43f60e01b815260040160405180910390fd5b6002601555610bbe6118dd565b610bc93385856120e4565b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015610c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6191906136aa565b50610c6a612145565b5060016015559392505050565b6000610c828361155a565b8210610ce45760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b606482015260840161098e565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6000844210610d2f5760405163af1a516560e01b815260040160405180910390fd5b85871115610d505760405163059a3ecf60e31b815260040160405180910390fd5b600088815260176020526040812080547fa0a7128942405265cd830695cb06df90c6bfdbbe22677cc592c3d36c3180b079918b9133918b919086610d93836136dd565b909155506040805160208101969096528501939093526001600160a01b039091166060840152608083015260a082015260c0810187905260e00160408051601f19818403018152828252805160209182012083830183526002845261190160f01b848301529151919350610e2c92917f0000000000000000000000000000000000000000000000000000000000000000918591016136f8565b60408051601f198184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610e97573d6000803e3d6000fd5b505050602060405103519050610ead818b611e46565b610eca57604051633a1d6db360e01b815260040160405180910390fd5b610ed58a8a33612225565b9a9950505050505050505050565b600060026015541415610f095760405163cbece43f60e01b815260040160405180910390fd5b6002601555610f166118dd565b610f22858585856122b9565b600160155595945050505050565b610b558383836040518060200160405280600081525061196b565b600060026015541415610f715760405163cbece43f60e01b815260040160405180910390fd5b600260155560165460ff16610f995760405163197b261160e21b815260040160405180910390fd5b610fa33384611e46565b610fc0576040516306a7959b60e21b815260040160405180910390fd5b506000828152600e60205260408082208054600c8054600160601b83046001600160581b031690819003909155600d80546001600160601b0390931692839003905582546001600160f81b03191683556001830194909455915163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529192917f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad91906136aa565b5050506110b8612145565b50600160155592915050565b60006110d03384611e46565b6110ed57604051633a1d6db360e01b815260040160405180910390fd5b6110f8838333612225565b9392505050565b60006b01419b9a3bada27fb800000082101561111d57506001919050565b6b02833734775b44ff7000000082101561113957506002919050565b6b06480a032a642c7e9800000082101561115557506003919050565b6b0c90140654c858fd3000000082101561117157506004919050565b6b1920280ca990b1fa6000000082101561118d57506005919050565b6b3aa05d72e0fc49f2e00000008210156111a957506006919050565b6b7da0c83f4fd379e3e00000008210156111c557506007919050565b6bfb41907e9fa6f3c7c00000008210156111e157506008919050565b6c01f68320fd3f4de78f800000008210156111fe57506009919050565b6c03ed0641fa7e9bcf1f0000000082101561121b5750600a919050565b6c082dcd097487c49a2b400000008210156112385750600b919050565b6c105b9a12e90f893456800000008210156112555750600c919050565b50600d919050565b600061126860085490565b82106112cb5760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b606482015260840161098e565b600882815481106112de576112de61371f565b90600052602060002001549050919050565b6000600260155414156113165760405163cbece43f60e01b815260040160405180910390fd5b60026015556113236118dd565b60405163d505accf60e01b8152336004820152306024820152604481018a90526064810186905260ff8516608482015260a4810184905260c481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d505accf9060e401600060405180830381600087803b1580156113af57600080fd5b505af11580156113c3573d6000803e3d6000fd5b505050506113d3898989896122b9565b60016015559998505050505050505050565b6013546001600160a01b0316331461140f576040516282b42960e81b815260040160405180910390fd5b7ff9c7803e94e0d3c02900d8a90893a6d5e90dd04d32a4cfe825520f82bf9f32f661143c60128484612eee565b6040516114499190613735565b60405180910390a15050565b6000818152600260205260408120546001600160a01b0316806108815760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b606482015260840161098e565b601280546114d99061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546115059061361e565b80156115525780601f1061152757610100808354040283529160200191611552565b820191906000526020600020905b81548152906001019060200180831161153557829003601f168201915b505050505081565b60006001600160a01b0382166115c55760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b606482015260840161098e565b506001600160a01b031660009081526003602052604090205490565b6013546001600160a01b0316331461160b576040516282b42960e81b815260040160405180910390fd5b601480546001600160a01b0319166001600160a01b03838116918217909255601354604051919216907fb51454ce8c7f26becd312a46c4815553887f2ec876a0b8dc813b87f62edf6f8090600090a350565b6014546001600160a01b03163314611687576040516282b42960e81b815260040160405180910390fd5b60135460405133916001600160a01b0316907f357bdeb5828fa83945f38a88510ce5cd7d628dafb346d767efbc693149fdd97c90600090a3601380546001600160a01b03199081163317909155601480549091169055565b6000818152600e6020526040812080546001600160601b03811690600160601b90046001600160581b0316806117166064846137ba565b61172091906137ef565b95945050505050565b600080600260155414156117505760405163cbece43f60e01b815260040160405180910390fd5b600260155561175d6118dd565b6117683389896120e4565b91506117778683878787612360565b9050611781612145565b5060016015559097909650945050505050565b6060600180546108969061361e565b6013546001600160a01b031633146117cd576040516282b42960e81b815260040160405180910390fd5b826117eb5760405163521299a960e01b815260040160405180910390fd5b60005b838110156118c757600085858381811061180a5761180a61371f565b90506020020135905060008484848181106118275761182761371f565b905060200201359050600082148061184257506312cc030082115b1561186057604051637616640160e01b815260040160405180910390fd5b60ff81111561188257604051631bc4bcf760e21b815260040160405180910390fd5b60008281526010602052604080822083905551829184917f9e9e076448196c8e3c3b1c02419e36f02935c786607a0e5b3e83ab8bf42526e19190a350506001016117ee565b5050505050565b6118d9338383612436565b5050565b60006118e7612145565b9050806118f15750565b600d5480611912576040516323127eed60e21b815260040160405180910390fd5b80604883901b81611925576119256137d9565b600a805492909104909101905560405182815233907f46749f2362413a5f0f53f7f11249e02052d810c56ead7bea2544c4a93a0828ee9060200160405180910390a25050565b6119753383611e46565b6119915760405162461bcd60e51b815260040161098e90613659565b61199d84848484612505565b50505050565b6000818152600260205260409020546060906001600160a01b03166119db5760405163677510db60e11b815260040160405180910390fd5b60126119e683612538565b6040516020016119f7929190613872565b6040516020818303038152906040529050919050565b6013546001600160a01b03163314611a37576040516282b42960e81b815260040160405180910390fd5b6016805460ff191660011790556040517f9e91804b7b70a36dcecd9afc85507eb02441c485502f58d0e68589aa50b8226a90600090a1565b6000818152600e6020526040812080546001820154600a546001600160601b038316020360481c600160601b9091046001600160581b0316016110f8565b60008060026015541415611ad45760405163cbece43f60e01b815260040160405180910390fd5b6002601555611ae16118dd565b611aeb3388612636565b9150611afa8683878787612360565b9050611b04612145565b50600160155590969095509350505050565b60008060018311611b3a57604051630aca66ef60e41b815260040160405180910390fd5b6000611b47600185613897565b90505b8015611bf657848482818110611b6257611b6261371f565b905060200201359250611b753384611e46565b611b92576040516306a7959b60e21b815260040160405180910390fd5b6000838152600e6020526040902054600160b81b900463ffffffff1615611bcc57604051631e98c21760e21b815260040160405180910390fd5b6000838152600f602052604081208054919055919091019060001901611bf18361277e565b611b4a565b84846000818110611c0957611c0961371f565b90506020020135925081600f60008581526020019081526020016000206000828254611c3591906138ae565b92505081905591507fa1f0ce30160de5720facdcbf1643907666c32930f9c145314028fd97b5126b5085858585604051611c7294939291906138c6565b60405180910390a1509250929050565b60606012604051602001611c96919061390f565b604051602081830303815290604052905090565b600060026015541415611cd05760405163cbece43f60e01b815260040160405180910390fd5b6002601555611cdd6118dd565b611ce73384612636565b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018390529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015611d5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7f91906136aa565b506110b8612145565b60006001600160e01b031982166380ac58cd60e01b1480611db957506001600160e01b03198216635b5e139f60e01b145b8061088157506301ffc9a760e01b6001600160e01b0319831614610881565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611e0d82611455565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b0316611ebf5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b606482015260840161098e565b6000611eca83611455565b9050806001600160a01b0316846001600160a01b03161480611f055750836001600160a01b0316611efa84610919565b6001600160a01b0316145b80611f3557506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b826001600160a01b0316611f5082611455565b6001600160a01b031614611fb45760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b606482015260840161098e565b6001600160a01b0382166120165760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161098e565b612021838383612825565b61202c600082611dd8565b6001600160a01b0383166000908152600360205260408120805460019290612055908490613897565b90915550506001600160a01b03821660009081526003602052604081208054600192906120839084906138ae565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6000816121045760405163521299a960e01b815260040160405180910390fd5b60005b8281101561213d57612131858585848181106121255761212561371f565b90506020020135612636565b90910190600101612107565b509392505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d2919061392f565b90506000600b5490506000600c5483116121ed5760006121f3565b600c5483035b905081811415612207576000935050505090565b600b8190558181101561221e576000935050505090565b0392915050565b6000838152600f602052604090205480831115612255576040516343fb945360e01b815260040160405180910390fd5b6000848152600f6020526040908190209184900391829055516001600160a01b0383169085907ff5173eb90ba2e438781051f8bf014fa2532624726c43ed8dacceb997e363bf2c906122aa9087815260200190565b60405180910390a39392505050565b6040516323b872dd60e01b8152336004820152306024820152604481018590526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303816000875af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235391906136aa565b50611720858585856128dd565b600084861115612383576040516305e8293760e51b815260040160405180910390fd5b61238f868585856128dd565b90508486146117205760405163a9059cbb60e01b81526001600160a01b03838116600483015287870360248301527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242c91906136aa565b5095945050505050565b816001600160a01b0316836001600160a01b031614156124985760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161098e565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b612510848484611f3d565b61251c84848484612aca565b61199d5760405162461bcd60e51b815260040161098e90613948565b60608161255c5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156125865780612570816136dd565b915061257f9050600a836137ef565b9150612560565b60008167ffffffffffffffff8111156125a1576125a1613477565b6040519080825280601f01601f1916602001820160405280156125cb576020820181803683370190505b5090505b8415611f35576125e0600183613897565b91506125ed600a8661399a565b6125f89060306138ae565b60f81b81838151811061260d5761260d61371f565b60200101906001600160f81b031916908160001a90535061262f600a866137ef565b94506125cf565b60006126428383611e46565b61265f576040516306a7959b60e21b815260040160405180910390fd5b6000828152600e6020526040902080546001600160601b03811690600160601b81046001600160581b031690600160b81b900463ffffffff16806126b657604051631916c98f60e31b815260040160405180910390fd5b80421080156126c8575060165460ff16155b156126e657604051630d9853e960e21b815260040160405180910390fd5b6001840154600a5484020360481c8201600c80548490039055600d805485900390556000878152600e602052604080822080546001600160f81b031916815560010191909155519095506001600160a01b0388169087907face2274efdcecc9282116630e8cb1c7f6156ca3cb8f3fde20c4c3d3fe64670429061276c9089815260200190565b60405180910390a35050505092915050565b600061278982611455565b905061279781600084612825565b6127a2600083611dd8565b6001600160a01b03811660009081526003602052604081208054600192906127cb908490613897565b909155505060008281526002602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b0383166128805761287b81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6128a3565b816001600160a01b0316836001600160a01b0316146128a3576128a38382612bc8565b6001600160a01b0382166128ba57610b5581612c65565b826001600160a01b0316826001600160a01b031614610b5557610b558282612d14565b60165460009060ff16156129045760405163481acfc960e11b815260040160405180910390fd5b6000848152601060205260409020548061293157604051637616640160e01b815260040160405180910390fd5b83811015612952576040516348f19e7760e11b815260040160405180910390fd5b601180546001019081905591508486026000838152600f6020526040902055600c805487019055606481870204670de0b6b3a76400008110156129a857604051630b4b2f1160e31b815260040160405180910390fd5b600d8054820190556040805160a0810182526001600160601b0380841682526001600160581b038a8116602080850191825263ffffffff428d8101821687890190815290821660608801908152600a549099026080880190815260008c8152600e855289902097518854955192519a518416600160d81b0263ffffffff60d81b199b909416600160b81b029a909a1667ffffffffffffffff60b81b1992909616600160601b026001600160b81b0319909516999096169890981792909217969096169190911717825551600191909101555187815286916001600160a01b0386169185917f90cb42f510ce5c0169b63666274740c2e6d975a476c3758664f3795699fc654e910160405180910390a4612ac18383612d58565b50949350505050565b60006001600160a01b0384163b15612bbd57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612b0e9033908990889088906004016139ae565b6020604051808303816000875af1925050508015612b49575060408051601f3d908101601f19168201909252612b46918101906139eb565b60015b612ba3573d808015612b77576040519150601f19603f3d011682016040523d82523d6000602084013e612b7c565b606091505b508051612b9b5760405162461bcd60e51b815260040161098e90613948565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611f35565b506001949350505050565b60006001612bd58461155a565b612bdf9190613897565b600083815260076020526040902054909150808214612c32576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090612c7790600190613897565b60008381526009602052604081205460088054939450909284908110612c9f57612c9f61371f565b906000526020600020015490508060088381548110612cc057612cc061371f565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480612cf857612cf8613a08565b6001900381819060005260206000200160009055905550505050565b6000612d1f8361155a565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6118d9828260405180602001604052806000815250612d778383612da0565b612d846000848484612aca565b610b555760405162461bcd60e51b815260040161098e90613948565b6001600160a01b038216612df65760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161098e565b6000818152600260205260409020546001600160a01b031615612e5b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161098e565b612e6760008383612825565b6001600160a01b0382166000908152600360205260408120805460019290612e909084906138ae565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b828054612efa9061361e565b90600052602060002090601f016020900481019282612f1c5760008555612f62565b82601f10612f355782800160ff19823516178555612f62565b82800160010185558215612f62579182015b82811115612f62578235825591602001919060010190612f47565b50612f6e929150612f72565b5090565b5b80821115612f6e5760008155600101612f73565b6001600160e01b031981168114612f9d57600080fd5b50565b600060208284031215612fb257600080fd5b81356110f881612f87565b60005b83811015612fd8578181015183820152602001612fc0565b8381111561199d5750506000910152565b60008151808452613001816020860160208601612fbd565b601f01601f19169290920160200192915050565b6020815260006110f86020830184612fe9565b60006020828403121561303a57600080fd5b5035919050565b80356001600160a01b038116811461305857600080fd5b919050565b6000806040838503121561307057600080fd5b61307983613041565b946020939093013593505050565b60008060006060848603121561309c57600080fd5b6130a584613041565b92506130b360208501613041565b9150604084013590509250925092565b60008083601f8401126130d557600080fd5b50813567ffffffffffffffff8111156130ed57600080fd5b6020830191508360208260051b850101111561310857600080fd5b9250929050565b60008060006040848603121561312457600080fd5b833567ffffffffffffffff81111561313b57600080fd5b613147868287016130c3565b909450925061315a905060208501613041565b90509250925092565b803560ff8116811461305857600080fd5b600080600080600080600060e0888a03121561318f57600080fd5b873596506020880135955060408801359450606088013593506131b460808901613163565b925060a0880135915060c0880135905092959891949750929550565b600080600080608085870312156131e657600080fd5b84359350602085013592506040850135915061320460608601613041565b905092959194509250565b6000806040838503121561322257600080fd5b8235915061323260208401613041565b90509250929050565b6000806040838503121561324e57600080fd5b50508035926020909101359150565b600080600080600080600080610100898b03121561327a57600080fd5b88359750602089013596506040890135955061329860608a01613041565b9450608089013593506132ad60a08a01613163565b925060c0890135915060e089013590509295985092959890939650565b600080602083850312156132dd57600080fd5b823567ffffffffffffffff808211156132f557600080fd5b818501915085601f83011261330957600080fd5b81358181111561331857600080fd5b86602082850101111561332a57600080fd5b60209290920196919550909350505050565b60006020828403121561334e57600080fd5b6110f882613041565b60008060008060008060a0878903121561337057600080fd5b863567ffffffffffffffff81111561338757600080fd5b61339389828a016130c3565b9097509550506020870135935060408701359250606087013591506133ba60808801613041565b90509295509295509295565b600080600080604085870312156133dc57600080fd5b843567ffffffffffffffff808211156133f457600080fd5b613400888389016130c3565b9096509450602087013591508082111561341957600080fd5b50613426878288016130c3565b95989497509550505050565b8015158114612f9d57600080fd5b6000806040838503121561345357600080fd5b61345c83613041565b9150602083013561346c81613432565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600080600080608085870312156134a357600080fd5b6134ac85613041565b93506134ba60208601613041565b925060408501359150606085013567ffffffffffffffff808211156134de57600080fd5b818701915087601f8301126134f257600080fd5b81358181111561350457613504613477565b604051601f8201601f19908116603f0116810190838211818310171561352c5761352c613477565b816040528281528a602084870101111561354557600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600080600080600060a0868803121561358157600080fd5b853594506020860135935060408601359250606086013591506135a660808701613041565b90509295509295909350565b600080602083850312156135c557600080fd5b823567ffffffffffffffff8111156135dc57600080fd5b6135e8858286016130c3565b90969095509350505050565b6000806040838503121561360757600080fd5b61361083613041565b915061323260208401613041565b600181811c9082168061363257607f821691505b6020821081141561365357634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6000602082840312156136bc57600080fd5b81516110f881613432565b634e487b7160e01b600052601160045260246000fd5b60006000198214156136f1576136f16136c7565b5060010190565b6000845161370a818460208901612fbd565b91909101928352506020820152604001919050565b634e487b7160e01b600052603260045260246000fd5b60006020808352600084546137498161361e565b8084870152604060018084166000811461376a576001811461377e576137ac565b60ff198516898401526060890195506137ac565b896000528660002060005b858110156137a45781548b8201860152908301908801613789565b8a0184019650505b509398975050505050505050565b60008160001904831182151516156137d4576137d46136c7565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826137fe576137fe6137d9565b500490565b600081546138108161361e565b60018281168015613828576001811461383957613868565b60ff19841687528287019450613868565b8560005260208060002060005b8581101561385f5781548a820152908401908201613846565b50505082870194505b5050505092915050565b600061387e8285613803565b835161388e818360208801612fbd565b01949350505050565b6000828210156138a9576138a96136c7565b500390565b600082198211156138c1576138c16136c7565b500190565b6060808252810184905260006001600160fb1b038511156138e657600080fd5b8460051b8087608085013760009083016080019081526020830194909452506040015292915050565b600061391b8284613803565b63696e666f60e01b81526004019392505050565b60006020828403121561394157600080fd5b5051919050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6000826139a9576139a96137d9565b500690565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906139e190830184612fe9565b9695505050505050565b6000602082840312156139fd57600080fd5b81516110f881612f87565b634e487b7160e01b600052603160045260246000fdfea264697066735822122008f44c4f44406741d7a1d635245021e57f69f96beed3fe60c42db712ac1b072f64736f6c634300080c003300000000000000000000000072b886d09c117654ab7da13a14d603001de0b7770000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c68747470733a2f2f7374616b696e672d6170692e78646566692e696f00000000

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061030c5760003560e01c80636c0360eb1161019d578063b7739ce1116100e9578063d3646e79116100a2578063e30c39781161007c578063e30c3978146107f2578063e8a3d48514610805578063e985e9c51461080d578063f1d2ec1d1461084957600080fd5b8063d3646e79146107ac578063d983103d146107cc578063de62d842146107df57600080fd5b8063b7739ce11461074c578063b88d4fde1461075e578063bd3a1adb14610771578063c87b56dd1461077e578063d009601014610791578063d1fdb3e81461079957600080fd5b80638ca31af911610156578063986419c711610130578063986419c714610715578063a22cb46514610728578063a83d4dda1461073b578063aa8badc11461074457600080fd5b80638ca31af9146106d25780638da5cb5b146106fa57806395d89b411461070d57600080fd5b80636c0360eb146106805780636d86acc41461068857806370a0823114610691578063710bf322146106a457806379ba5097146106b75780637f082d22146106bf57600080fd5b806330be763e1161025c5780634eeea7ad1161021557806350da4ed7116101ef57806350da4ed71461063857806355f804b31461064b578063579d13b81461065e5780636352211e1461066d57600080fd5b80634eeea7ad146105ff5780634f062c5a146106125780634f6ccce71461062557600080fd5b806330be763e1461048057806335b2b215146104935780633644e515146104a657806342842e0e146104cd57806346f96023146104e05780634db1bb96146105ec57600080fd5b80630fed817f116102c957806323b872dd116102a357806323b872dd146104275780632f588cd41461043a5780632f745c591461044d578063306536bd1461046057600080fd5b80630fed817f146103d857806318160ddd146103ff5780631c5898091461040757600080fd5b806301ffc9a71461031157806306fdde0314610339578063074737421461034e578063081812fc1461036557806309363c4414610390578063095ea7b3146103c3575b600080fd5b61032461031f366004612fa0565b61085c565b60405190151581526020015b60405180910390f35b610341610887565b6040516103309190613015565b610357600c5481565b604051908152602001610330565b610378610373366004613028565b610919565b6040516001600160a01b039091168152602001610330565b6103a361039e366004613028565b6109b3565b604080519485526020850193909352918301526060820152608001610330565b6103d66103d136600461305d565b610a44565b005b6103787f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b77781565b600854610357565b610357610415366004613028565b600f6020526000908152604090205481565b6103d6610435366004613087565b610b5a565b61035761044836600461310f565b610b8b565b61035761045b36600461305d565b610c77565b61035761046e366004613028565b60176020526000908152604090205481565b61035761048e366004613174565b610d0d565b6103576104a13660046131d0565b610ee3565b6103577f5e45f0ffc5dd07026136d7ab4929cc6765dd281e0a5a02560cff3c591341196081565b6103d66104db366004613087565b610f30565b61058c6104ee366004613028565b6040805160a081018252600080825260208201819052918101829052606081018290526080810191909152506000908152600e6020908152604091829020825160a08101845281546001600160601b03811682526001600160581b03600160601b8204169382019390935263ffffffff600160b81b8404811694820194909452600160d81b9092049092166060820152600190910154608082015290565b6040516103309190600060a0820190506001600160601b0383511682526001600160581b036020840151166020830152604083015163ffffffff808216604085015280606086015116606085015250506080830151608083015292915050565b6103576105fa36600461320f565b610f4b565b61035761060d36600461323b565b6110c4565b610357610620366004613028565b6110ff565b610357610633366004613028565b61125d565b61035761064636600461325d565b6112f0565b6103d66106593660046132ca565b6113e5565b610357670de0b6b3a764000081565b61037861067b366004613028565b611455565b6103416114cc565b610357600d5481565b61035761069f36600461333c565b61155a565b6103d66106b236600461333c565b6115e1565b6103d661165d565b6103576106cd366004613028565b6116df565b6106e56106e0366004613357565b611729565b60408051928352602083019190915201610330565b601354610378906001600160a01b031681565b610341611794565b6103d66107233660046133c6565b6117a3565b6103d6610736366004613440565b6118ce565b610357600b5481565b6103d66118dd565b61035761075a36600461323b565b0290565b6103d661076c36600461348d565b61196b565b6016546103249060ff1681565b61034161078c366004613028565b6119a3565b6103d6611a0d565b6103576107a7366004613028565b611a6f565b6103576107ba366004613028565b60106020526000908152604090205481565b6106e56107da366004613569565b611aad565b6106e56107ed3660046135b2565b611b16565b601454610378906001600160a01b031681565b610341611c82565b61032461081b3660046135f4565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b61035761085736600461320f565b611caa565b60006001600160e01b0319821663780e9d6360e01b1480610881575061088182611d88565b92915050565b6060600080546108969061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546108c29061361e565b801561090f5780601f106108e45761010080835404028352916020019161090f565b820191906000526020600020905b8154815290600101906020018083116108f257829003601f168201915b5050505050905090565b6000818152600260205260408120546001600160a01b03166109975760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a20617070726f76656420717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b60648201526084015b60405180910390fd5b506000908152600460205260409020546001600160a01b031690565b6000806000806109da856000908152600260205260409020546001600160a01b0316151590565b6109f75760405163677510db60e11b815260040160405180910390fd5b6000858152600f60205260409020549250610a11836110ff565b9350610a1c85611a6f565b6000958652600e6020526040909520549395929493600160b81b900463ffffffff1692915050565b6000610a4f82611455565b9050806001600160a01b0316836001600160a01b03161415610abd5760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b606482015260840161098e565b336001600160a01b0382161480610ad95750610ad9813361081b565b610b4b5760405162461bcd60e51b815260206004820152603860248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f74206f7760448201527f6e6572206e6f7220617070726f76656420666f7220616c6c0000000000000000606482015260840161098e565b610b558383611dd8565b505050565b610b643382611e46565b610b805760405162461bcd60e51b815260040161098e90613659565b610b55838383611f3d565b600060026015541415610bb15760405163cbece43f60e01b815260040160405180910390fd5b6002601555610bbe6118dd565b610bc93385856120e4565b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018390529192507f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b7779091169063a9059cbb906044016020604051808303816000875af1158015610c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6191906136aa565b50610c6a612145565b5060016015559392505050565b6000610c828361155a565b8210610ce45760405162461bcd60e51b815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201526a74206f6620626f756e647360a81b606482015260840161098e565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6000844210610d2f5760405163af1a516560e01b815260040160405180910390fd5b85871115610d505760405163059a3ecf60e31b815260040160405180910390fd5b600088815260176020526040812080547fa0a7128942405265cd830695cb06df90c6bfdbbe22677cc592c3d36c3180b079918b9133918b919086610d93836136dd565b909155506040805160208101969096528501939093526001600160a01b039091166060840152608083015260a082015260c0810187905260e00160408051601f19818403018152828252805160209182012083830183526002845261190160f01b848301529151919350610e2c92917f5e45f0ffc5dd07026136d7ab4929cc6765dd281e0a5a02560cff3c5913411960918591016136f8565b60408051601f198184030181528282528051602091820120600080855291840180845281905260ff89169284019290925260608301879052608083018690529092509060019060a0016020604051602081039080840390855afa158015610e97573d6000803e3d6000fd5b505050602060405103519050610ead818b611e46565b610eca57604051633a1d6db360e01b815260040160405180910390fd5b610ed58a8a33612225565b9a9950505050505050505050565b600060026015541415610f095760405163cbece43f60e01b815260040160405180910390fd5b6002601555610f166118dd565b610f22858585856122b9565b600160155595945050505050565b610b558383836040518060200160405280600081525061196b565b600060026015541415610f715760405163cbece43f60e01b815260040160405180910390fd5b600260155560165460ff16610f995760405163197b261160e21b815260040160405180910390fd5b610fa33384611e46565b610fc0576040516306a7959b60e21b815260040160405180910390fd5b506000828152600e60205260408082208054600c8054600160601b83046001600160581b031690819003909155600d80546001600160601b0390931692839003905582546001600160f81b03191683556001830194909455915163a9059cbb60e01b81526001600160a01b038581166004830152602482018590529192917f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b777169063a9059cbb906044016020604051808303816000875af1158015611089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110ad91906136aa565b5050506110b8612145565b50600160155592915050565b60006110d03384611e46565b6110ed57604051633a1d6db360e01b815260040160405180910390fd5b6110f8838333612225565b9392505050565b60006b01419b9a3bada27fb800000082101561111d57506001919050565b6b02833734775b44ff7000000082101561113957506002919050565b6b06480a032a642c7e9800000082101561115557506003919050565b6b0c90140654c858fd3000000082101561117157506004919050565b6b1920280ca990b1fa6000000082101561118d57506005919050565b6b3aa05d72e0fc49f2e00000008210156111a957506006919050565b6b7da0c83f4fd379e3e00000008210156111c557506007919050565b6bfb41907e9fa6f3c7c00000008210156111e157506008919050565b6c01f68320fd3f4de78f800000008210156111fe57506009919050565b6c03ed0641fa7e9bcf1f0000000082101561121b5750600a919050565b6c082dcd097487c49a2b400000008210156112385750600b919050565b6c105b9a12e90f893456800000008210156112555750600c919050565b50600d919050565b600061126860085490565b82106112cb5760405162461bcd60e51b815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201526b7574206f6620626f756e647360a01b606482015260840161098e565b600882815481106112de576112de61371f565b90600052602060002001549050919050565b6000600260155414156113165760405163cbece43f60e01b815260040160405180910390fd5b60026015556113236118dd565b60405163d505accf60e01b8152336004820152306024820152604481018a90526064810186905260ff8516608482015260a4810184905260c481018390527f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b7776001600160a01b03169063d505accf9060e401600060405180830381600087803b1580156113af57600080fd5b505af11580156113c3573d6000803e3d6000fd5b505050506113d3898989896122b9565b60016015559998505050505050505050565b6013546001600160a01b0316331461140f576040516282b42960e81b815260040160405180910390fd5b7ff9c7803e94e0d3c02900d8a90893a6d5e90dd04d32a4cfe825520f82bf9f32f661143c60128484612eee565b6040516114499190613735565b60405180910390a15050565b6000818152600260205260408120546001600160a01b0316806108815760405162461bcd60e51b815260206004820152602960248201527f4552433732313a206f776e657220717565727920666f72206e6f6e657869737460448201526832b73a103a37b5b2b760b91b606482015260840161098e565b601280546114d99061361e565b80601f01602080910402602001604051908101604052809291908181526020018280546115059061361e565b80156115525780601f1061152757610100808354040283529160200191611552565b820191906000526020600020905b81548152906001019060200180831161153557829003601f168201915b505050505081565b60006001600160a01b0382166115c55760405162461bcd60e51b815260206004820152602a60248201527f4552433732313a2062616c616e636520717565727920666f7220746865207a65604482015269726f206164647265737360b01b606482015260840161098e565b506001600160a01b031660009081526003602052604090205490565b6013546001600160a01b0316331461160b576040516282b42960e81b815260040160405180910390fd5b601480546001600160a01b0319166001600160a01b03838116918217909255601354604051919216907fb51454ce8c7f26becd312a46c4815553887f2ec876a0b8dc813b87f62edf6f8090600090a350565b6014546001600160a01b03163314611687576040516282b42960e81b815260040160405180910390fd5b60135460405133916001600160a01b0316907f357bdeb5828fa83945f38a88510ce5cd7d628dafb346d767efbc693149fdd97c90600090a3601380546001600160a01b03199081163317909155601480549091169055565b6000818152600e6020526040812080546001600160601b03811690600160601b90046001600160581b0316806117166064846137ba565b61172091906137ef565b95945050505050565b600080600260155414156117505760405163cbece43f60e01b815260040160405180910390fd5b600260155561175d6118dd565b6117683389896120e4565b91506117778683878787612360565b9050611781612145565b5060016015559097909650945050505050565b6060600180546108969061361e565b6013546001600160a01b031633146117cd576040516282b42960e81b815260040160405180910390fd5b826117eb5760405163521299a960e01b815260040160405180910390fd5b60005b838110156118c757600085858381811061180a5761180a61371f565b90506020020135905060008484848181106118275761182761371f565b905060200201359050600082148061184257506312cc030082115b1561186057604051637616640160e01b815260040160405180910390fd5b60ff81111561188257604051631bc4bcf760e21b815260040160405180910390fd5b60008281526010602052604080822083905551829184917f9e9e076448196c8e3c3b1c02419e36f02935c786607a0e5b3e83ab8bf42526e19190a350506001016117ee565b5050505050565b6118d9338383612436565b5050565b60006118e7612145565b9050806118f15750565b600d5480611912576040516323127eed60e21b815260040160405180910390fd5b80604883901b81611925576119256137d9565b600a805492909104909101905560405182815233907f46749f2362413a5f0f53f7f11249e02052d810c56ead7bea2544c4a93a0828ee9060200160405180910390a25050565b6119753383611e46565b6119915760405162461bcd60e51b815260040161098e90613659565b61199d84848484612505565b50505050565b6000818152600260205260409020546060906001600160a01b03166119db5760405163677510db60e11b815260040160405180910390fd5b60126119e683612538565b6040516020016119f7929190613872565b6040516020818303038152906040529050919050565b6013546001600160a01b03163314611a37576040516282b42960e81b815260040160405180910390fd5b6016805460ff191660011790556040517f9e91804b7b70a36dcecd9afc85507eb02441c485502f58d0e68589aa50b8226a90600090a1565b6000818152600e6020526040812080546001820154600a546001600160601b038316020360481c600160601b9091046001600160581b0316016110f8565b60008060026015541415611ad45760405163cbece43f60e01b815260040160405180910390fd5b6002601555611ae16118dd565b611aeb3388612636565b9150611afa8683878787612360565b9050611b04612145565b50600160155590969095509350505050565b60008060018311611b3a57604051630aca66ef60e41b815260040160405180910390fd5b6000611b47600185613897565b90505b8015611bf657848482818110611b6257611b6261371f565b905060200201359250611b753384611e46565b611b92576040516306a7959b60e21b815260040160405180910390fd5b6000838152600e6020526040902054600160b81b900463ffffffff1615611bcc57604051631e98c21760e21b815260040160405180910390fd5b6000838152600f602052604081208054919055919091019060001901611bf18361277e565b611b4a565b84846000818110611c0957611c0961371f565b90506020020135925081600f60008581526020019081526020016000206000828254611c3591906138ae565b92505081905591507fa1f0ce30160de5720facdcbf1643907666c32930f9c145314028fd97b5126b5085858585604051611c7294939291906138c6565b60405180910390a1509250929050565b60606012604051602001611c96919061390f565b604051602081830303815290604052905090565b600060026015541415611cd05760405163cbece43f60e01b815260040160405180910390fd5b6002601555611cdd6118dd565b611ce73384612636565b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018390529192507f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b7779091169063a9059cbb906044016020604051808303816000875af1158015611d5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7f91906136aa565b506110b8612145565b60006001600160e01b031982166380ac58cd60e01b1480611db957506001600160e01b03198216635b5e139f60e01b145b8061088157506301ffc9a760e01b6001600160e01b0319831614610881565b600081815260046020526040902080546001600160a01b0319166001600160a01b0384169081179091558190611e0d82611455565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b6000818152600260205260408120546001600160a01b0316611ebf5760405162461bcd60e51b815260206004820152602c60248201527f4552433732313a206f70657261746f7220717565727920666f72206e6f6e657860448201526b34b9ba32b73a103a37b5b2b760a11b606482015260840161098e565b6000611eca83611455565b9050806001600160a01b0316846001600160a01b03161480611f055750836001600160a01b0316611efa84610919565b6001600160a01b0316145b80611f3557506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b949350505050565b826001600160a01b0316611f5082611455565b6001600160a01b031614611fb45760405162461bcd60e51b815260206004820152602560248201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060448201526437bbb732b960d91b606482015260840161098e565b6001600160a01b0382166120165760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b606482015260840161098e565b612021838383612825565b61202c600082611dd8565b6001600160a01b0383166000908152600360205260408120805460019290612055908490613897565b90915550506001600160a01b03821660009081526003602052604081208054600192906120839084906138ae565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b0386811691821790925591518493918716917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6000816121045760405163521299a960e01b815260040160405180910390fd5b60005b8281101561213d57612131858585848181106121255761212561371f565b90506020020135612636565b90910190600101612107565b509392505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b77716906370a0823190602401602060405180830381865afa1580156121ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d2919061392f565b90506000600b5490506000600c5483116121ed5760006121f3565b600c5483035b905081811415612207576000935050505090565b600b8190558181101561221e576000935050505090565b0392915050565b6000838152600f602052604090205480831115612255576040516343fb945360e01b815260040160405180910390fd5b6000848152600f6020526040908190209184900391829055516001600160a01b0383169085907ff5173eb90ba2e438781051f8bf014fa2532624726c43ed8dacceb997e363bf2c906122aa9087815260200190565b60405180910390a39392505050565b6040516323b872dd60e01b8152336004820152306024820152604481018590526000907f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b7776001600160a01b0316906323b872dd906064016020604051808303816000875af115801561232f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061235391906136aa565b50611720858585856128dd565b600084861115612383576040516305e8293760e51b815260040160405180910390fd5b61238f868585856128dd565b90508486146117205760405163a9059cbb60e01b81526001600160a01b03838116600483015287870360248301527f00000000000000000000000072b886d09c117654ab7da13a14d603001de0b777169063a9059cbb906044016020604051808303816000875af1158015612408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061242c91906136aa565b5095945050505050565b816001600160a01b0316836001600160a01b031614156124985760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c657200000000000000604482015260640161098e565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b612510848484611f3d565b61251c84848484612aca565b61199d5760405162461bcd60e51b815260040161098e90613948565b60608161255c5750506040805180820190915260018152600360fc1b602082015290565b8160005b81156125865780612570816136dd565b915061257f9050600a836137ef565b9150612560565b60008167ffffffffffffffff8111156125a1576125a1613477565b6040519080825280601f01601f1916602001820160405280156125cb576020820181803683370190505b5090505b8415611f35576125e0600183613897565b91506125ed600a8661399a565b6125f89060306138ae565b60f81b81838151811061260d5761260d61371f565b60200101906001600160f81b031916908160001a90535061262f600a866137ef565b94506125cf565b60006126428383611e46565b61265f576040516306a7959b60e21b815260040160405180910390fd5b6000828152600e6020526040902080546001600160601b03811690600160601b81046001600160581b031690600160b81b900463ffffffff16806126b657604051631916c98f60e31b815260040160405180910390fd5b80421080156126c8575060165460ff16155b156126e657604051630d9853e960e21b815260040160405180910390fd5b6001840154600a5484020360481c8201600c80548490039055600d805485900390556000878152600e602052604080822080546001600160f81b031916815560010191909155519095506001600160a01b0388169087907face2274efdcecc9282116630e8cb1c7f6156ca3cb8f3fde20c4c3d3fe64670429061276c9089815260200190565b60405180910390a35050505092915050565b600061278982611455565b905061279781600084612825565b6127a2600083611dd8565b6001600160a01b03811660009081526003602052604081208054600192906127cb908490613897565b909155505060008281526002602052604080822080546001600160a01b0319169055518391906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b6001600160a01b0383166128805761287b81600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6128a3565b816001600160a01b0316836001600160a01b0316146128a3576128a38382612bc8565b6001600160a01b0382166128ba57610b5581612c65565b826001600160a01b0316826001600160a01b031614610b5557610b558282612d14565b60165460009060ff16156129045760405163481acfc960e11b815260040160405180910390fd5b6000848152601060205260409020548061293157604051637616640160e01b815260040160405180910390fd5b83811015612952576040516348f19e7760e11b815260040160405180910390fd5b601180546001019081905591508486026000838152600f6020526040902055600c805487019055606481870204670de0b6b3a76400008110156129a857604051630b4b2f1160e31b815260040160405180910390fd5b600d8054820190556040805160a0810182526001600160601b0380841682526001600160581b038a8116602080850191825263ffffffff428d8101821687890190815290821660608801908152600a549099026080880190815260008c8152600e855289902097518854955192519a518416600160d81b0263ffffffff60d81b199b909416600160b81b029a909a1667ffffffffffffffff60b81b1992909616600160601b026001600160b81b0319909516999096169890981792909217969096169190911717825551600191909101555187815286916001600160a01b0386169185917f90cb42f510ce5c0169b63666274740c2e6d975a476c3758664f3795699fc654e910160405180910390a4612ac18383612d58565b50949350505050565b60006001600160a01b0384163b15612bbd57604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290612b0e9033908990889088906004016139ae565b6020604051808303816000875af1925050508015612b49575060408051601f3d908101601f19168201909252612b46918101906139eb565b60015b612ba3573d808015612b77576040519150601f19603f3d011682016040523d82523d6000602084013e612b7c565b606091505b508051612b9b5760405162461bcd60e51b815260040161098e90613948565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050611f35565b506001949350505050565b60006001612bd58461155a565b612bdf9190613897565b600083815260076020526040902054909150808214612c32576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090612c7790600190613897565b60008381526009602052604081205460088054939450909284908110612c9f57612c9f61371f565b906000526020600020015490508060088381548110612cc057612cc061371f565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480612cf857612cf8613a08565b6001900381819060005260206000200160009055905550505050565b6000612d1f8361155a565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b6118d9828260405180602001604052806000815250612d778383612da0565b612d846000848484612aca565b610b555760405162461bcd60e51b815260040161098e90613948565b6001600160a01b038216612df65760405162461bcd60e51b815260206004820181905260248201527f4552433732313a206d696e7420746f20746865207a65726f2061646472657373604482015260640161098e565b6000818152600260205260409020546001600160a01b031615612e5b5760405162461bcd60e51b815260206004820152601c60248201527f4552433732313a20746f6b656e20616c7265616479206d696e74656400000000604482015260640161098e565b612e6760008383612825565b6001600160a01b0382166000908152600360205260408120805460019290612e909084906138ae565b909155505060008181526002602052604080822080546001600160a01b0319166001600160a01b03861690811790915590518392907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b828054612efa9061361e565b90600052602060002090601f016020900481019282612f1c5760008555612f62565b82601f10612f355782800160ff19823516178555612f62565b82800160010185558215612f62579182015b82811115612f62578235825591602001919060010190612f47565b50612f6e929150612f72565b5090565b5b80821115612f6e5760008155600101612f73565b6001600160e01b031981168114612f9d57600080fd5b50565b600060208284031215612fb257600080fd5b81356110f881612f87565b60005b83811015612fd8578181015183820152602001612fc0565b8381111561199d5750506000910152565b60008151808452613001816020860160208601612fbd565b601f01601f19169290920160200192915050565b6020815260006110f86020830184612fe9565b60006020828403121561303a57600080fd5b5035919050565b80356001600160a01b038116811461305857600080fd5b919050565b6000806040838503121561307057600080fd5b61307983613041565b946020939093013593505050565b60008060006060848603121561309c57600080fd5b6130a584613041565b92506130b360208501613041565b9150604084013590509250925092565b60008083601f8401126130d557600080fd5b50813567ffffffffffffffff8111156130ed57600080fd5b6020830191508360208260051b850101111561310857600080fd5b9250929050565b60008060006040848603121561312457600080fd5b833567ffffffffffffffff81111561313b57600080fd5b613147868287016130c3565b909450925061315a905060208501613041565b90509250925092565b803560ff8116811461305857600080fd5b600080600080600080600060e0888a03121561318f57600080fd5b873596506020880135955060408801359450606088013593506131b460808901613163565b925060a0880135915060c0880135905092959891949750929550565b600080600080608085870312156131e657600080fd5b84359350602085013592506040850135915061320460608601613041565b905092959194509250565b6000806040838503121561322257600080fd5b8235915061323260208401613041565b90509250929050565b6000806040838503121561324e57600080fd5b50508035926020909101359150565b600080600080600080600080610100898b03121561327a57600080fd5b88359750602089013596506040890135955061329860608a01613041565b9450608089013593506132ad60a08a01613163565b925060c0890135915060e089013590509295985092959890939650565b600080602083850312156132dd57600080fd5b823567ffffffffffffffff808211156132f557600080fd5b818501915085601f83011261330957600080fd5b81358181111561331857600080fd5b86602082850101111561332a57600080fd5b60209290920196919550909350505050565b60006020828403121561334e57600080fd5b6110f882613041565b60008060008060008060a0878903121561337057600080fd5b863567ffffffffffffffff81111561338757600080fd5b61339389828a016130c3565b9097509550506020870135935060408701359250606087013591506133ba60808801613041565b90509295509295509295565b600080600080604085870312156133dc57600080fd5b843567ffffffffffffffff808211156133f457600080fd5b613400888389016130c3565b9096509450602087013591508082111561341957600080fd5b50613426878288016130c3565b95989497509550505050565b8015158114612f9d57600080fd5b6000806040838503121561345357600080fd5b61345c83613041565b9150602083013561346c81613432565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600080600080608085870312156134a357600080fd5b6134ac85613041565b93506134ba60208601613041565b925060408501359150606085013567ffffffffffffffff808211156134de57600080fd5b818701915087601f8301126134f257600080fd5b81358181111561350457613504613477565b604051601f8201601f19908116603f0116810190838211818310171561352c5761352c613477565b816040528281528a602084870101111561354557600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600080600080600060a0868803121561358157600080fd5b853594506020860135935060408601359250606086013591506135a660808701613041565b90509295509295909350565b600080602083850312156135c557600080fd5b823567ffffffffffffffff8111156135dc57600080fd5b6135e8858286016130c3565b90969095509350505050565b6000806040838503121561360757600080fd5b61361083613041565b915061323260208401613041565b600181811c9082168061363257607f821691505b6020821081141561365357634e487b7160e01b600052602260045260246000fd5b50919050565b60208082526031908201527f4552433732313a207472616e736665722063616c6c6572206973206e6f74206f6040820152701ddb995c881b9bdc88185c1c1c9bdd9959607a1b606082015260800190565b6000602082840312156136bc57600080fd5b81516110f881613432565b634e487b7160e01b600052601160045260246000fd5b60006000198214156136f1576136f16136c7565b5060010190565b6000845161370a818460208901612fbd565b91909101928352506020820152604001919050565b634e487b7160e01b600052603260045260246000fd5b60006020808352600084546137498161361e565b8084870152604060018084166000811461376a576001811461377e576137ac565b60ff198516898401526060890195506137ac565b896000528660002060005b858110156137a45781548b8201860152908301908801613789565b8a0184019650505b509398975050505050505050565b60008160001904831182151516156137d4576137d46136c7565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826137fe576137fe6137d9565b500490565b600081546138108161361e565b60018281168015613828576001811461383957613868565b60ff19841687528287019450613868565b8560005260208060002060005b8581101561385f5781548a820152908401908201613846565b50505082870194505b5050505092915050565b600061387e8285613803565b835161388e818360208801612fbd565b01949350505050565b6000828210156138a9576138a96136c7565b500390565b600082198211156138c1576138c16136c7565b500190565b6060808252810184905260006001600160fb1b038511156138e657600080fd5b8460051b8087608085013760009083016080019081526020830194909452506040015292915050565b600061391b8284613803565b63696e666f60e01b81526004019392505050565b60006020828403121561394157600080fd5b5051919050565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6000826139a9576139a96137d9565b500690565b6001600160a01b03858116825284166020820152604081018390526080606082018190526000906139e190830184612fe9565b9695505050505050565b6000602082840312156139fd57600080fd5b81516110f881612f87565b634e487b7160e01b600052603160045260246000fdfea264697066735822122008f44c4f44406741d7a1d635245021e57f69f96beed3fe60c42db712ac1b072f64736f6c634300080c0033

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

00000000000000000000000072b886d09c117654ab7da13a14d603001de0b7770000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c68747470733a2f2f7374616b696e672d6170692e78646566692e696f00000000

-----Decoded View---------------
Arg [0] : xdefi_ (address): 0x72B886d09C117654aB7dA13A14d603001dE0B777
Arg [1] : baseURI_ (string): https://staking-api.xdefi.io

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000072b886d09c117654ab7da13a14d603001de0b777
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 000000000000000000000000000000000000000000000000000000000000001c
Arg [3] : 68747470733a2f2f7374616b696e672d6170692e78646566692e696f00000000


Deployed Bytecode Sourcemap

57886:28062:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;51562:224;;;;;;:::i;:::-;;:::i;:::-;;;565:14:1;;558:22;540:41;;528:2;513:18;51562:224:0;;;;;;;;38382:100;;;:::i;:::-;;;;;;;:::i;60163:34::-;;;;;;;;;1489:25:1;;;1477:2;1462:18;60163:34:0;1343:177:1;39941:221:0;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1874:32:1;;;1856:51;;1844:2;1829:18;39941:221:0;1710:203:1;71534:527:0;;;;;;:::i;:::-;;:::i;:::-;;;;2149:25:1;;;2205:2;2190:18;;2183:34;;;;2233:18;;;2226:34;2291:2;2276:18;;2269:34;2136:3;2121:19;71534:527:0;1918:391:1;39464:411:0;;;;;;:::i;:::-;;:::i;:::-;;60084:30;;;;;52202:113;52290:10;:17;52202:113;;60296:44;;;;;;:::i;:::-;;;;;;;;;;;;;;40691:339;;;;;;:::i;:::-;;:::i;70942:507::-;;;;;;:::i;:::-;;:::i;51870:256::-;;;;;;:::i;:::-;;:::i;61094:53::-;;;;;;:::i;:::-;;;;;;;;;;;;;;72531:1463;;;;;;:::i;:::-;;:::i;66725:301::-;;;;;;:::i;:::-;;:::i;61044:41::-;;;;;41101:185;;;;;;:::i;:::-;;:::i;67616:140::-;;;;;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;67727:21:0;;;;:11;:21;;;;;;;;;67715:33;;;;;;;;;-1:-1:-1;;;;;67715:33:0;;;;-1:-1:-1;;;;;;;;67715:33:0;;;;;;;;;;;-1:-1:-1;;;67715:33:0;;;;;;;;;;;-1:-1:-1;;;67715:33:0;;;;;;;;;;;;;;;;;;;;67616:140;;;;;;;5452:4:1;5494:3;5483:9;5479:19;5471:27;;-1:-1:-1;;;;;5535:6:1;5529:13;5525:46;5514:9;5507:65;-1:-1:-1;;;;;5632:4:1;5624:6;5620:17;5614:24;5610:55;5603:4;5592:9;5588:20;5581:85;5713:4;5705:6;5701:17;5695:24;5738:10;5804:2;5790:12;5786:21;5779:4;5768:9;5764:20;5757:51;5876:2;5868:4;5860:6;5856:17;5850:24;5846:33;5839:4;5828:9;5824:20;5817:63;;;5936:4;5928:6;5924:17;5918:24;5911:4;5900:9;5896:20;5889:54;5310:639;;;;;64911:1409:0;;;;;;:::i;:::-;;:::i;72069:454::-;;;;;;:::i;:::-;;:::i;74451:819::-;;;;;;:::i;:::-;;:::i;52392:233::-;;;;;;:::i;:::-;;:::i;67034:574::-;;;;;;:::i;:::-;;:::i;63739:119::-;;;;;;:::i;:::-;;:::i;60982:53::-;;61030:4;60982:53;;38076:239;;;;;;:::i;:::-;;:::i;60515:21::-;;;:::i;60204:25::-;;;;;;37806:208;;;;;;:::i;:::-;;:::i;63593:138::-;;;;;;:::i;:::-;;:::i;63215:229::-;;;:::i;66328:389::-;;;;;;:::i;:::-;;:::i;70357:577::-;;;;;;:::i;:::-;;:::i;:::-;;;;8824:25:1;;;8880:2;8865:18;;8858:34;;;;8797:18;70357:577:0;8650:248:1;60545:20:0;;;;;-1:-1:-1;;;;;60545:20:0;;;38551:104;;;:::i;63866:945::-;;;;;;:::i;:::-;;:::i;40234:155::-;;;;;;:::i;:::-;;:::i;60123:33::-;;;;;;68846:1108;;;:::i;74159:284::-;;;;;;:::i;:::-;74405:19;;74159:284;41357:328;;;;;;:::i;:::-;;:::i;60779:27::-;;;;;;;;;76996:322;;;;;;:::i;:::-;;:::i;63452:133::-;;;:::i;69962:277::-;;;;;;:::i;:::-;;:::i;60349:52::-;;;;;;:::i;:::-;;;;;;;;;;;;;;67764:568;;;;;;:::i;:::-;;:::i;75278:1710::-;;;;;;:::i;:::-;;:::i;60572:27::-;;;;;-1:-1:-1;;;;;60572:27:0;;;74002:149;;;:::i;40460:164::-;;;;;;:::i;:::-;-1:-1:-1;;;;;40581:25:0;;;40557:4;40581:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;;;40460:164;68340:498;;;;;;:::i;:::-;;:::i;51562:224::-;51664:4;-1:-1:-1;;;;;;51688:50:0;;-1:-1:-1;;;51688:50:0;;:90;;;51742:36;51766:11;51742:23;:36::i;:::-;51681:97;51562:224;-1:-1:-1;;51562:224:0:o;38382:100::-;38436:13;38469:5;38462:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;38382:100;:::o;39941:221::-;40017:7;43284:16;;;:7;:16;;;;;;-1:-1:-1;;;;;43284:16:0;40037:73;;;;-1:-1:-1;;;40037:73:0;;13158:2:1;40037:73:0;;;13140:21:1;13197:2;13177:18;;;13170:30;13236:34;13216:18;;;13209:62;-1:-1:-1;;;13287:18:1;;;13280:42;13339:19;;40037:73:0;;;;;;;;;-1:-1:-1;40130:24:0;;;;:15;:24;;;;;;-1:-1:-1;;;;;40130:24:0;;39941:221::o;71534:527::-;71638:13;71666:16;71697:21;71733:15;71829:17;71837:8;43260:4;43284:16;;;:7;:16;;;;;;-1:-1:-1;;;;;43284:16:0;:30;;;43195:127;71829:17;71824:50;;71855:19;;-1:-1:-1;;;71855:19:0;;;;;;;;;;;71824:50;71898:19;;;;:9;:19;;;;;;;-1:-1:-1;71936:17:0;71898:19;71936:7;:17::i;:::-;71928:25;;71980:24;71995:8;71980:14;:24::i;:::-;72025:21;;;;:11;:21;;;;;;:28;71534:527;;;;72025:21;-1:-1:-1;;;72025:28:0;;;;;71534:527;-1:-1:-1;;71534:527:0:o;39464:411::-;39545:13;39561:23;39576:7;39561:14;:23::i;:::-;39545:39;;39609:5;-1:-1:-1;;;;;39603:11:0;:2;-1:-1:-1;;;;;39603:11:0;;;39595:57;;;;-1:-1:-1;;;39595:57:0;;13571:2:1;39595:57:0;;;13553:21:1;13610:2;13590:18;;;13583:30;13649:34;13629:18;;;13622:62;-1:-1:-1;;;13700:18:1;;;13693:31;13741:19;;39595:57:0;13369:397:1;39595:57:0;6054:10;-1:-1:-1;;;;;39687:21:0;;;;:62;;-1:-1:-1;39712:37:0;39729:5;6054:10;40460:164;:::i;39712:37::-;39665:168;;;;-1:-1:-1;;;39665:168:0;;13973:2:1;39665:168:0;;;13955:21:1;14012:2;13992:18;;;13985:30;14051:34;14031:18;;;14024:62;14122:26;14102:18;;;14095:54;14166:19;;39665:168:0;13771:420:1;39665:168:0;39846:21;39855:2;39859:7;39846:8;:21::i;:::-;39534:341;39464:411;;:::o;40691:339::-;40886:41;6054:10;40919:7;40886:18;:41::i;:::-;40878:103;;;;-1:-1:-1;;;40878:103:0;;;;;;;:::i;:::-;40994:28;41004:4;41010:2;41014:7;40994:9;:28::i;70942:507::-;71095:23;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;62839:20:::1;:18;:20::i;:::-;71230:35:::3;71243:10;71255:9;;71230:12;:35::i;:::-;71388:53;::::0;-1:-1:-1;;;71388:53:0;;-1:-1:-1;;;;;14806:32:1;;;71388:53:0::3;::::0;::::3;14788:51:1::0;14855:18;;;14848:34;;;71212:53:0;;-1:-1:-1;71395:5:0::3;71388:22:::0;;::::3;::::0;::::3;::::0;14761:18:1;;71388:53:0::3;;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;63089:27:::2;:25;:27::i;:::-;-1:-1:-1::0;60658:1:0;62745:13;:29;70942:507;;-1:-1:-1;;;70942:507:0:o;51870:256::-;51967:7;52003:23;52020:5;52003:16;:23::i;:::-;51995:5;:31;51987:87;;;;-1:-1:-1;;;51987:87:0;;15345:2:1;51987:87:0;;;15327:21:1;15384:2;15364:18;;;15357:30;15423:34;15403:18;;;15396:62;-1:-1:-1;;;15474:18:1;;;15467:41;15525:19;;51987:87:0;15143:407:1;51987:87:0;-1:-1:-1;;;;;;52092:19:0;;;;;;;;:12;:19;;;;;;;;:26;;;;;;;;;51870:256::o;72531:1463::-;72750:25;72873:9;72854:15;:28;72850:63;;72891:22;;-1:-1:-1;;;72891:22:0;;;;;;;;;;;72850:63;73032:6;73022:7;:16;73018:49;;;73047:20;;-1:-1:-1;;;73047:20:0;;;;;;;;;;;73018:49;73220:14;73319:28;;;:18;:28;;;;;:30;;61422:66;;73289:8;;73299:10;;73311:6;;73319:30;73220:14;73319:30;;;:::i;:::-;;;;-1:-1:-1;73247:114:0;;;;;;16114:25:1;;;;16155:18;;16148:34;;;;-1:-1:-1;;;;;16218:32:1;;;16198:18;;;16191:60;16267:18;;;16260:34;16310:19;;;16303:35;16354:19;;;16347:35;;;16086:19;;73247:114:0;;;-1:-1:-1;;73247:114:0;;;;;;;;;73237:125;;73247:114;73237:125;;;;73468:40;;;;;;;;-1:-1:-1;;;73468:40:0;;;;73451:84;;73237:125;;-1:-1:-1;73451:84:0;;73247:114;73510:16;;73237:125;;73451:84;;:::i;:::-;;;;-1:-1:-1;;73451:84:0;;;;;;;;;73441:95;;73451:84;73441:95;;;;73549:24;73576:29;;;;;;;;;17064:25:1;;;17137:4;17125:17;;17105:18;;;17098:45;;;;17159:18;;;17152:34;;;17202:18;;;17195:34;;;73441:95:0;;-1:-1:-1;73549:24:0;73576:29;;17036:19:1;;73576:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;73549:56;;73788:46;73807:16;73825:8;73788:18;:46::i;:::-;73783:82;;73843:22;;-1:-1:-1;;;73843:22:0;;;;;;;;;;;73783:82;73947:39;73956:8;73966:7;73975:10;73947:8;:39::i;:::-;73927:59;72531:1463;-1:-1:-1;;;;;;;;;;72531:1463:0:o;66725:301::-;66921:16;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;62839:20:::1;:18;:20::i;:::-;66961:57:::2;66967:7;66976:9;66987:16;67005:12;66961:5;:57::i;:::-;60658:1:::0;62745:13;:29;66950:68;66725:301;-1:-1:-1;;;;;66725:301:0:o;41101:185::-;41239:39;41256:4;41262:2;41266:7;41239:39;;;;;;;;;;;;:16;:39::i;64911:1409::-;65029:23;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;65115:15:::2;::::0;::::2;;65110:49;;65139:20;;-1:-1:-1::0;;;65139:20:0::2;;;;;;;;;;;65110:49;65314:40;65333:10;65345:8;65314:18;:40::i;:::-;65309:81;;65363:27;;-1:-1:-1::0;;;65363:27:0::2;;;;;;;;;;;65309:81;-1:-1:-1::0;65431:25:0::2;65459:21:::0;;;:11:::2;:21;::::0;;;;;65515:14;;65567:23:::2;65810:38:::0;;-1:-1:-1;;;65567:23:0;::::2;-1:-1:-1::0;;;;;65567:23:0::2;65810:38:::0;;;::::2;::::0;;;66065:10:::2;:19:::0;;-1:-1:-1;;;;;65515:14:0;;::::2;66065:19:::0;;;::::2;::::0;;66108:28;;-1:-1:-1;;;;;;66108:28:0;;;-1:-1:-1;66108:28:0;::::2;::::0;;;;66259:53;;-1:-1:-1;;;66259:53:0;;-1:-1:-1;;;;;14806:32:1;;;66259:53:0::2;::::0;::::2;14788:51:1::0;14855:18;;;14848:34;;;65459:21:0;;65515:14;66266:5:::2;66259:22;::::0;::::2;::::0;14761:18:1;;66259:53:0::2;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;65054:1266;;63089:27:::1;:25;:27::i;:::-;-1:-1:-1::0;60658:1:0;62745:13;:29;64911:1409;;-1:-1:-1;;64911:1409:0:o;72069:454::-;72139:25;72323:40;72342:10;72354:8;72323:18;:40::i;:::-;72318:76;;72372:22;;-1:-1:-1;;;72372:22:0;;;;;;;;;;;72318:76;72476:39;72485:8;72495:7;72504:10;72476:8;:39::i;:::-;72456:59;72069:454;-1:-1:-1;;;72069:454:0:o;74451:819::-;74507:13;58943:20;74537:8;:27;74533:46;;;-1:-1:-1;58247:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74533:46::-;59024:20;74596:8;:27;74592:46;;;-1:-1:-1;58299:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74592:46::-;59105:20;74655:8;:27;74651:46;;;-1:-1:-1;58351:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74651:46::-;59186:22;74714:8;:27;74710:46;;;-1:-1:-1;58403:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74710:46::-;59269:22;74773:8;:27;74769:46;;;-1:-1:-1;58455:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74769:46::-;59352:22;74832:8;:27;74828:46;;;-1:-1:-1;58507:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74828:46::-;59435:23;74891:8;:27;74887:46;;;-1:-1:-1;58559:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74887:46::-;59519:23;74950:8;:27;74946:46;;;-1:-1:-1;58611:1:0;;74451:819;-1:-1:-1;74451:819:0:o;74946:46::-;59604:23;75009:8;:28;75005:47;;;-1:-1:-1;58663:1:0;;74451:819;-1:-1:-1;74451:819:0:o;75005:47::-;59689:24;75069:8;:28;75065:48;;;-1:-1:-1;58716:2:0;;74451:819;-1:-1:-1;74451:819:0:o;75065:48::-;59775:24;75130:8;:28;75126:48;;;-1:-1:-1;58770:2:0;;74451:819;-1:-1:-1;74451:819:0:o;75126:48::-;59861:24;75191:8;:28;75187:48;;;-1:-1:-1;58824:2:0;;74451:819;-1:-1:-1;74451:819:0:o;75187:48::-;-1:-1:-1;58878:2:0;;74451:819;-1:-1:-1;74451:819:0:o;52392:233::-;52467:7;52503:30;52290:10;:17;;52202:113;52503:30;52495:5;:38;52487:95;;;;-1:-1:-1;;;52487:95:0;;17442:2:1;52487:95:0;;;17424:21:1;17481:2;17461:18;;;17454:30;17520:34;17500:18;;;17493:62;-1:-1:-1;;;17571:18:1;;;17564:42;17623:19;;52487:95:0;17240:408:1;52487:95:0;52600:10;52611:5;52600:17;;;;;;;;:::i;:::-;;;;;;;;;52593:24;;52392:233;;;:::o;67034:574::-;67329:16;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;62839:20:::1;:18;:20::i;:::-;67438:81:::2;::::0;-1:-1:-1;;;67438:81:0;;67461:10:::2;67438:81;::::0;::::2;18134:34:1::0;67481:4:0::2;18184:18:1::0;;;18177:43;18236:18;;;18229:34;;;18279:18;;;18272:34;;;18355:4;18343:17;;18322:19;;;18315:46;18377:19;;;18370:35;;;18421:19;;;18414:35;;;67447:5:0::2;-1:-1:-1::0;;;;;67438:22:0::2;::::0;::::2;::::0;18068:19:1;;67438:81:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;;;;;67543:57;67549:7;67558:9;67569:16;67587:12;67543:5;:57::i;:::-;60658:1:::0;62745:13;:29;67532:68;67034:574;-1:-1:-1;;;;;;;;;67034:574:0:o;63739:119::-;62527:5;;-1:-1:-1;;;;;62527:5:0;62536:10;62527:19;62523:46;;62555:14;;-1:-1:-1;;;62555:14:0;;;;;;;;;;;62523:46;63820:30:::1;63831:18;:7;63841:8:::0;;63831:18:::1;:::i;:::-;63820:30;;;;;;:::i;:::-;;;;;;;;63739:119:::0;;:::o;38076:239::-;38148:7;38184:16;;;:7;:16;;;;;;-1:-1:-1;;;;;38184:16:0;38219:19;38211:73;;;;-1:-1:-1;;;38211:73:0;;19593:2:1;38211:73:0;;;19575:21:1;19632:2;19612:18;;;19605:30;19671:34;19651:18;;;19644:62;-1:-1:-1;;;19722:18:1;;;19715:39;19771:19;;38211:73:0;19391:405:1;60515:21:0;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;37806:208::-;37878:7;-1:-1:-1;;;;;37906:19:0;;37898:74;;;;-1:-1:-1;;;37898:74:0;;20003:2:1;37898:74:0;;;19985:21:1;20042:2;20022:18;;;20015:30;20081:34;20061:18;;;20054:62;-1:-1:-1;;;20132:18:1;;;20125:40;20182:19;;37898:74:0;19801:406:1;37898:74:0;-1:-1:-1;;;;;;37990:16:0;;;;;:9;:16;;;;;;;37806:208::o;63593:138::-;62527:5;;-1:-1:-1;;;;;62527:5:0;62536:10;62527:19;62523:46;;62555:14;;-1:-1:-1;;;62555:14:0;;;;;;;;;;;62523:46;63698:12:::1;:24:::0;;-1:-1:-1;;;;;;63698:24:0::1;-1:-1:-1::0;;;;;63698:24:0;;::::1;::::0;;::::1;::::0;;;63691:5:::1;::::0;63673:50:::1;::::0;63698:24;;63691:5:::1;::::0;63673:50:::1;::::0;-1:-1:-1;;63673:50:0::1;63593:138:::0;:::o;63215:229::-;63266:12;;-1:-1:-1;;;;;63266:12:0;63282:10;63266:26;63262:53;;63301:14;;-1:-1:-1;;;63301:14:0;;;;;;;;;;;63262:53;63351:5;;63333:36;;63358:10;;-1:-1:-1;;;;;63351:5:0;;63333:36;;63351:5;;63333:36;63380:5;:18;;-1:-1:-1;;;;;;63380:18:0;;;63388:10;63380:18;;;;63409:12;:27;;;;;;;63215:229::o;66328:389::-;66399:24;66492:21;;;:11;:21;;;;;66548:14;;-1:-1:-1;;;;;66548:14:0;;;-1:-1:-1;;;66607:23:0;;-1:-1:-1;;;;;66607:23:0;;66664:27;58191:3;66548:14;66664:27;:::i;:::-;66663:46;;;;:::i;:::-;66644:65;66328:389;-1:-1:-1;;;;;66328:389:0:o;70357:577::-;70628:23;70653:19;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;62839:20:::1;:18;:20::i;:::-;70784:35:::3;70797:10;70809:9;;70784:12;:35::i;:::-;70766:53;;70846:80;70854:11;70867:15;70884:9;70895:16;70913:12;70846:7;:80::i;:::-;70832:94;;63089:27:::2;:25;:27::i;:::-;-1:-1:-1::0;60658:1:0;62745:13;:29;70357:577;;;;-1:-1:-1;70357:577:0;-1:-1:-1;;;;;70357:577:0:o;38551:104::-;38607:13;38640:7;38633:14;;;;;:::i;63866:945::-;62527:5;;-1:-1:-1;;;;;62527:5:0;62536:10;62527:19;62523:46;;62555:14;;-1:-1:-1;;;62555:14:0;;;;;;;;;;;62523:46;64116:33;64112:58:::1;;64158:12;;-1:-1:-1::0;;;64158:12:0::1;;;;;;;;;;;64112:58;64188:9;64183:621;64199:21:::0;;::::1;64183:621;;;64239:16;64258:10;;64269:1;64258:13;;;;;;;:::i;:::-;;;;;;;64239:32;;64286:18;64307:12;;64320:1;64307:15;;;;;;;:::i;:::-;;;;;;;64286:36;;58069:1;64411:8;:24;:51;;;;60864:17;64439:8;:23;64411:51;64407:81;;;64471:17;;-1:-1:-1::0;;;64471:17:0::1;;;;;;;;;;;64407:81;60959:3;64580:10;:33;64576:65;;;64622:19;;-1:-1:-1::0;;;64622:19:0::1;;;;;;;;;;;64576:65;64687:27;::::0;;;:17:::1;:27;::::0;;;;;:40;;;64663:65;64717:10;;64705:8;;64663:65:::1;::::0;64687:27;64663:65:::1;-1:-1:-1::0;;64774:3:0::1;;64183:621;;;;63866:945:::0;;;;:::o;40234:155::-;40329:52;6054:10;40362:8;40372;40329:18;:52::i;:::-;40234:155;;:::o;68846:1108::-;69076:36;69115:27;:25;:27::i;:::-;69076:66;-1:-1:-1;69215:44:0;69211:57;;69261:7;68846:1108::o;69211:57::-;69307:10;;69437:32;69433:59;;69478:14;;-1:-1:-1;;;69478:14:0;;;;;;;;;;;69433:59;69840:16;60034:2;69782:28;:54;;69781:75;;;;;:::i;:::-;69763:14;:93;;69781:75;;;;69763:93;;;;;69885:61;;1489:25:1;;;69905:10:0;;69885:61;;1477:2:1;1462:18;69885:61:0;;;;;;;68883:1071;;68846:1108::o;41357:328::-;41532:41;6054:10;41565:7;41532:18;:41::i;:::-;41524:103;;;;-1:-1:-1;;;41524:103:0;;;;;;;:::i;:::-;41638:39;41652:4;41658:2;41662:7;41671:5;41638:13;:39::i;:::-;41357:328;;;;:::o;76996:322::-;43260:4;43284:16;;;:7;:16;;;;;;77090:23;;-1:-1:-1;;;;;43284:16:0;77174:50;;77205:19;;-1:-1:-1;;;77205:19:0;;;;;;;;;;;77174:50;77273:7;77282:26;77299:8;77282:16;:26::i;:::-;77256:53;;;;;;;;;:::i;:::-;;;;;;;;;;;;;77237:73;;76996:322;;;:::o;63452:133::-;62527:5;;-1:-1:-1;;;;;62527:5:0;62536:10;62527:19;62523:46;;62555:14;;-1:-1:-1;;;62555:14:0;;;;;;;;;;;62523:46;63515:15:::1;:22:::0;;-1:-1:-1;;63515:22:0::1;63533:4;63515:22;::::0;;63553:24:::1;::::0;::::1;::::0;63515:15:::1;::::0;63553:24:::1;63452:133::o:0;69962:277::-;70025:26;70092:21;;;:11;:21;;;;;70164:14;;;70205:25;;;85836:14;;-1:-1:-1;;;;;70164:14:0;;85836:23;85835:45;60034:2;85834:73;-1:-1:-1;;;70180:23:0;;;-1:-1:-1;;;;;70180:23:0;85833:93;70145:86;85105:840;67764:568;68018:23;68043:19;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;62839:20:::1;:18;:20::i;:::-;68173:44:::3;68196:10;68208:8;68173:22;:44::i;:::-;68155:62;;68244:80;68252:11;68265:15;68282:9;68293:16;68311:12;68244:7;:80::i;:::-;68230:94;;63089:27:::2;:25;:27::i;:::-;-1:-1:-1::0;60658:1:0;62745:13;:29;67764:568;;;;-1:-1:-1;67764:568:0;-1:-1:-1;;;;67764:568:0:o;75278:1710::-;75341:16;;58126:1;75467:31;;75463:63;;75507:19;;-1:-1:-1;;;75507:19:0;;;;;;;;;;;75463:63;75539:16;75558:20;75577:1;75558:9;:20;:::i;:::-;75539:39;;75711:920;75718:23;;75711:920;;75769:9;;75779:8;75769:19;;;;;;;:::i;:::-;;;;;;;75758:30;;75955:40;75974:10;75986:8;75955:18;:40::i;:::-;75950:81;;76004:27;;-1:-1:-1;;;76004:27:0;;;;;;;;;;;75950:81;58069:1;76140:21;;;:11;:21;;;;;:28;-1:-1:-1;;;76140:28:0;;;;:44;76136:78;;76193:21;;-1:-1:-1;;;76193:21:0;;;;;;;;;;;76136:78;76411:19;;;;:9;:19;;;;;;;76563:26;;;76399:31;;;;;-1:-1:-1;;76451:10:0;76604:15;76421:8;76604:5;:15::i;:::-;75711:920;;;76709:9;;76719:1;76709:12;;;;;;;:::i;:::-;;;;;;;76698:23;;76910:8;76887:9;:19;76897:8;76887:19;;;;;;;;;;;;:31;;;;;;;:::i;:::-;;;;;;;76875:44;;76937:43;76950:9;;76961:8;76971;76937:43;;;;;;;;;:::i;:::-;;;;;;;;75377:1611;75278:1710;;;;;:::o;74002:149::-;74048:26;74126:7;74109:33;;;;;;;;:::i;:::-;;;;;;;;;;;;;74087:56;;74002:149;:::o;68340:498::-;68476:23;60713:1;62635:13;;:26;62631:53;;;62670:14;;-1:-1:-1;;;62670:14:0;;;;;;;;;;;62631:53;60713:1;62697:13;:25;62839:20:::1;:18;:20::i;:::-;68610:44:::3;68633:10;68645:8;68610:22;:44::i;:::-;68777:53;::::0;-1:-1:-1;;;68777:53:0;;-1:-1:-1;;;;;14806:32:1;;;68777:53:0::3;::::0;::::3;14788:51:1::0;14855:18;;;14848:34;;;68592:62:0;;-1:-1:-1;68784:5:0::3;68777:22:::0;;::::3;::::0;::::3;::::0;14761:18:1;;68777:53:0::3;;;;;;;;;;;;;;;;;;::::0;::::3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;63089:27:::2;:25;:27::i;37437:305::-:0;37539:4;-1:-1:-1;;;;;;37576:40:0;;-1:-1:-1;;;37576:40:0;;:105;;-1:-1:-1;;;;;;;37633:48:0;;-1:-1:-1;;;37633:48:0;37576:105;:158;;;-1:-1:-1;;;;;;;;;;17613:40:0;;;37698:36;17504:157;47341:174;47416:24;;;;:15;:24;;;;;:29;;-1:-1:-1;;;;;;47416:29:0;-1:-1:-1;;;;;47416:29:0;;;;;;;;:24;;47470:23;47416:24;47470:14;:23::i;:::-;-1:-1:-1;;;;;47461:46:0;;;;;;;;;;;47341:174;;:::o;43489:348::-;43582:4;43284:16;;;:7;:16;;;;;;-1:-1:-1;;;;;43284:16:0;43599:73;;;;-1:-1:-1;;;43599:73:0;;23182:2:1;43599:73:0;;;23164:21:1;23221:2;23201:18;;;23194:30;23260:34;23240:18;;;23233:62;-1:-1:-1;;;23311:18:1;;;23304:42;23363:19;;43599:73:0;22980:408:1;43599:73:0;43683:13;43699:23;43714:7;43699:14;:23::i;:::-;43683:39;;43752:5;-1:-1:-1;;;;;43741:16:0;:7;-1:-1:-1;;;;;43741:16:0;;:51;;;;43785:7;-1:-1:-1;;;;;43761:31:0;:20;43773:7;43761:11;:20::i;:::-;-1:-1:-1;;;;;43761:31:0;;43741:51;:87;;;-1:-1:-1;;;;;;40581:25:0;;;40557:4;40581:25;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;43796:32;43733:96;43489:348;-1:-1:-1;;;;43489:348:0:o;46598:625::-;46757:4;-1:-1:-1;;;;;46730:31:0;:23;46745:7;46730:14;:23::i;:::-;-1:-1:-1;;;;;46730:31:0;;46722:81;;;;-1:-1:-1;;;46722:81:0;;23595:2:1;46722:81:0;;;23577:21:1;23634:2;23614:18;;;23607:30;23673:34;23653:18;;;23646:62;-1:-1:-1;;;23724:18:1;;;23717:35;23769:19;;46722:81:0;23393:401:1;46722:81:0;-1:-1:-1;;;;;46822:16:0;;46814:65;;;;-1:-1:-1;;;46814:65:0;;24001:2:1;46814:65:0;;;23983:21:1;24040:2;24020:18;;;24013:30;24079:34;24059:18;;;24052:62;-1:-1:-1;;;24130:18:1;;;24123:34;24174:19;;46814:65:0;23799:400:1;46814:65:0;46892:39;46913:4;46919:2;46923:7;46892:20;:39::i;:::-;46996:29;47013:1;47017:7;46996:8;:29::i;:::-;-1:-1:-1;;;;;47038:15:0;;;;;;:9;:15;;;;;:20;;47057:1;;47038:15;:20;;47057:1;;47038:20;:::i;:::-;;;;-1:-1:-1;;;;;;;47069:13:0;;;;;;:9;:13;;;;;:18;;47086:1;;47069:13;:18;;47086:1;;47069:18;:::i;:::-;;;;-1:-1:-1;;47098:16:0;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;47098:21:0;-1:-1:-1;;;;;47098:21:0;;;;;;;;;47137:27;;47098:16;;47137:27;;;;;;;39534:341;39464:411;;:::o;83539:605::-;83627:23;83787:32;83783:57;;83828:12;;-1:-1:-1;;;83828:12:0;;;;;;;;;;;83783:57;83942:9;83937:200;83953:20;;;83937:200;;;84040:46;84063:8;84073:9;;84083:1;84073:12;;;;;;;:::i;:::-;;;;;;;84040:22;:46::i;:::-;84021:65;;;;84107:3;;83937:200;;;;83539:605;;;;;:::o;84152:945::-;84280:38;;-1:-1:-1;;;84280:38:0;;84312:4;84280:38;;;1856:51:1;84207:37:0;;;;-1:-1:-1;;;;;84287:5:0;84280:23;;;;1829:18:1;;84280:38:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;84257:61;;84329:34;84366:18;;84329:55;;84422:33;84473:19;;84458:12;:34;:86;;58069:1;84458:86;;;84510:19;;84495:12;:34;84458:86;84422:122;;84664:26;84635:25;:55;84631:80;;;58069:1;84692:19;;;;;84152:945;:::o;84631:80::-;84768:18;:46;;;84900:54;;;84896:79;;;58069:1;84956:19;;;;;84152:945;:::o;84896:79::-;85024:54;;84152:945;-1:-1:-1;;84152:945:0:o;77418:580::-;77542:25;77600:19;;;:9;:19;;;;;;77711:27;;;77707:61;;;77747:21;;-1:-1:-1;;;77747:21:0;;;;;;;;;;;77707:61;77864:19;;;;:9;:19;;;;;;;77887:28;;;;77864:52;;;;77945:45;-1:-1:-1;;;;;77945:45:0;;;77874:8;;77945:45;;;;77908:7;1489:25:1;;1477:2;1462:18;;1343:177;77945:45:0;;;;;;;;77418:580;;;;;:::o;82016:544::-;82303:62;;-1:-1:-1;;;82303:62:0;;82330:10;82303:62;;;24633:34:1;82350:4:0;24683:18:1;;;24676:43;24735:18;;;24728:34;;;82176:16:0;;82310:5;-1:-1:-1;;;;;82303:26:0;;;;24568:18:1;;82303:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;82479:73;82501:7;82510:9;82521:16;82539:12;82479:21;:73::i;82568:963::-;82768:16;82952:15;82938:11;:29;82934:70;;;82976:28;;-1:-1:-1;;;82976:28:0;;;;;;;;;;;82934:70;83118:77;83140:11;83153:9;83164:16;83182:12;83118:21;:77::i;:::-;83107:88;-1:-1:-1;83237:45:0;;;83233:280;;83430:67;;-1:-1:-1;;;83430:67:0;;-1:-1:-1;;;;;14806:32:1;;;83430:67:0;;;14788:51:1;83467:29:0;;;14855:18:1;;;14848:34;83437:5:0;83430:22;;;;14761:18:1;;83430:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;82568:963;;;;;;;:::o;47657:315::-;47812:8;-1:-1:-1;;;;;47803:17:0;:5;-1:-1:-1;;;;;47803:17:0;;;47795:55;;;;-1:-1:-1;;;47795:55:0;;24975:2:1;47795:55:0;;;24957:21:1;25014:2;24994:18;;;24987:30;25053:27;25033:18;;;25026:55;25098:18;;47795:55:0;24773:349:1;47795:55:0;-1:-1:-1;;;;;47861:25:0;;;;;;;:18;:25;;;;;;;;:35;;;;;;;;;;;;;:46;;-1:-1:-1;;47861:46:0;;;;;;;;;;47923:41;;540::1;;;47923::0;;513:18:1;47923:41:0;;;;;;;47657:315;;;:::o;42567:::-;42724:28;42734:4;42740:2;42744:7;42724:9;:28::i;:::-;42771:48;42794:4;42800:2;42804:7;42813:5;42771:22;:48::i;:::-;42763:111;;;;-1:-1:-1;;;42763:111:0;;;;;;;:::i;3536:723::-;3592:13;3813:10;3809:53;;-1:-1:-1;;3840:10:0;;;;;;;;;;;;-1:-1:-1;;;3840:10:0;;;;;3536:723::o;3809:53::-;3887:5;3872:12;3928:78;3935:9;;3928:78;;3961:8;;;;:::i;:::-;;-1:-1:-1;3984:10:0;;-1:-1:-1;3992:2:0;3984:10;;:::i;:::-;;;3928:78;;;4016:19;4048:6;4038:17;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4038:17:0;;4016:39;;4066:154;4073:10;;4066:154;;4100:11;4110:1;4100:11;;:::i;:::-;;-1:-1:-1;4169:10:0;4177:2;4169:5;:10;:::i;:::-;4156:24;;:2;:24;:::i;:::-;4143:39;;4126:6;4133;4126:14;;;;;;;;:::i;:::-;;;;:56;-1:-1:-1;;;;;4126:56:0;;;;;;;;-1:-1:-1;4197:11:0;4206:2;4197:11;;:::i;:::-;;;4066:154;;80201:1807;80287:23;80467:38;80486:8;80496;80467:18;:38::i;:::-;80462:79;;80514:27;;-1:-1:-1;;;80514:27:0;;;;;;;;;;;80462:79;80582:25;80610:21;;;:11;:21;;;;;80666:14;;-1:-1:-1;;;;;80666:14:0;;;-1:-1:-1;;;80725:23:0;;-1:-1:-1;;;;;80725:23:0;;-1:-1:-1;;;80785:15:0;;;;;80915:60;;80950:25;;-1:-1:-1;;;80950:25:0;;;;;;;;;;;80915:60;81165:6;81147:15;:24;:44;;;;-1:-1:-1;81176:15:0;;;;81175:16;81147:44;81143:71;;;81200:14;;-1:-1:-1;;;81200:14:0;;;;;;;;;;;81143:71;81354:25;;;;85836:14;;:23;;85835:45;60034:2;85834:73;85833:93;;81599:19;:37;;;;;;;81853:10;:19;;;;;;;81599;81903:21;;;:11;:21;;;;;;81896:28;;-1:-1:-1;;;;;;81896:28:0;;;-1:-1:-1;81896:28:0;;;;;81942:58;81294:86;;-1:-1:-1;;;;;;81942:58:0;;;81915:8;;81942:58;;;;81294:86;1489:25:1;;1477:2;1462:18;;1343:177;81942:58:0;;;;;;;;80312:1696;;;;80201:1807;;;;:::o;45841:420::-;45901:13;45917:23;45932:7;45917:14;:23::i;:::-;45901:39;;45953:48;45974:5;45989:1;45993:7;45953:20;:48::i;:::-;46042:29;46059:1;46063:7;46042:8;:29::i;:::-;-1:-1:-1;;;;;46084:16:0;;;;;;:9;:16;;;;;:21;;46104:1;;46084:16;:21;;46104:1;;46084:21;:::i;:::-;;;;-1:-1:-1;;46123:16:0;;;;:7;:16;;;;;;46116:23;;-1:-1:-1;;;;;;46116:23:0;;;46157:36;46131:7;;46123:16;-1:-1:-1;;;;;46157:36:0;;;;;46123:16;;46157:36;40234:155;;:::o;53238:589::-;-1:-1:-1;;;;;53444:18:0;;53440:187;;53479:40;53511:7;54654:10;:17;;54627:24;;;;:15;:24;;;;;:44;;;54682:24;;;;;;;;;;;;54550:164;53479:40;53440:187;;;53549:2;-1:-1:-1;;;;;53541:10:0;:4;-1:-1:-1;;;;;53541:10:0;;53537:90;;53568:47;53601:4;53607:7;53568:32;:47::i;:::-;-1:-1:-1;;;;;53641:16:0;;53637:183;;53674:45;53711:7;53674:36;:45::i;53637:183::-;53747:4;-1:-1:-1;;;;;53741:10:0;:2;-1:-1:-1;;;;;53741:10:0;;53737:83;;53768:40;53796:2;53800:7;53768:27;:40::i;78006:2187::-;78264:15;;78182:16;;78264:15;;78260:47;;;78288:19;;-1:-1:-1;;;78288:19:0;;;;;;;;;;;78260:47;78320:23;78346:28;;;:17;:28;;;;;;78443:31;78439:61;;78483:17;;-1:-1:-1;;;78483:17:0;;;;;;;;;;;78439:61;78613:16;78595:15;:34;78591:73;;;78638:26;;-1:-1:-1;;;78638:26:0;;;;;;;;;;;78591:73;78752:13;78750:15;;;;;;;;;-1:-1:-1;74405:19:0;;;78813;;;;:9;:19;;;;;:52;78914:19;:30;;;;;;58191:3;79032:25;;;79031:49;61030:4;79194:21;;79190:60;;;79224:26;;-1:-1:-1;;;79224:26:0;;;;;;;;;;;79190:60;79267:10;:19;;;;;;79327:654;;;;;;;;-1:-1:-1;;;;;79327:654:0;;;;;-1:-1:-1;;;;;79327:654:0;;;;;;;;;;;79607:15;:27;;;79327:654;;;;;;;;;;;;;;;;;79881:14;;:22;;;79327:654;;;;;;-1:-1:-1;79303:21:0;;;:11;:21;;;;;:678;;;;;;;;;;;;-1:-1:-1;;;79303:678:0;-1:-1:-1;;;;79303:678:0;;;;-1:-1:-1;;;79303:678:0;;;;;-1:-1:-1;;;;79303:678:0;;;;-1:-1:-1;;;79303:678:0;-1:-1:-1;;;;;;79303:678:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;79303:678:0;;;;;80010:63;1489:25:1;;;79607:27:0;;-1:-1:-1;;;;;80010:63:0;;;79303:21;;80010:63;;1462:18:1;80010:63:0;;;;;;;80152:33;80162:12;80176:8;80152:9;:33::i;:::-;78200:1993;78006:2187;;;;;;:::o;48537:799::-;48692:4;-1:-1:-1;;;;;48713:13:0;;7716:19;:23;48709:620;;48749:72;;-1:-1:-1;;;48749:72:0;;-1:-1:-1;;;;;48749:36:0;;;;;:72;;6054:10;;48800:4;;48806:7;;48815:5;;48749:72;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;-1:-1:-1;48749:72:0;;;;;;;;-1:-1:-1;;48749:72:0;;;;;;;;;;;;:::i;:::-;;;48745:529;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;48991:13:0;;48987:272;;49034:60;;-1:-1:-1;;;49034:60:0;;;;;;;:::i;48987:272::-;49209:6;49203:13;49194:6;49190:2;49186:15;49179:38;48745:529;-1:-1:-1;;;;;;48872:51:0;-1:-1:-1;;;48872:51:0;;-1:-1:-1;48865:58:0;;48709:620;-1:-1:-1;49313:4:0;48537:799;;;;;;:::o;55341:988::-;55607:22;55657:1;55632:22;55649:4;55632:16;:22::i;:::-;:26;;;;:::i;:::-;55669:18;55690:26;;;:17;:26;;;;;;55607:51;;-1:-1:-1;55823:28:0;;;55819:328;;-1:-1:-1;;;;;55890:18:0;;55868:19;55890:18;;;:12;:18;;;;;;;;:34;;;;;;;;;55941:30;;;;;;:44;;;56058:30;;:17;:30;;;;;:43;;;55819:328;-1:-1:-1;56243:26:0;;;;:17;:26;;;;;;;;56236:33;;;-1:-1:-1;;;;;56287:18:0;;;;;:12;:18;;;;;:34;;;;;;;56280:41;55341:988::o;56624:1079::-;56902:10;:17;56877:22;;56902:21;;56922:1;;56902:21;:::i;:::-;56934:18;56955:24;;;:15;:24;;;;;;57328:10;:26;;56877:46;;-1:-1:-1;56955:24:0;;56877:46;;57328:26;;;;;;:::i;:::-;;;;;;;;;57306:48;;57392:11;57367:10;57378;57367:22;;;;;;;;:::i;:::-;;;;;;;;;;;;:36;;;;57472:28;;;:15;:28;;;;;;;:41;;;57644:24;;;;;57637:31;57679:10;:16;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;56695:1008;;;56624:1079;:::o;54128:221::-;54213:14;54230:20;54247:2;54230:16;:20::i;:::-;-1:-1:-1;;;;;54261:16:0;;;;;;;:12;:16;;;;;;;;:24;;;;;;;;:34;;;54306:26;;;:17;:26;;;;;;:35;;;;-1:-1:-1;54128:221:0:o;44179:110::-;44255:26;44265:2;44269:7;44255:26;;;;;;;;;;;;44646:18;44652:2;44656:7;44646:5;:18::i;:::-;44697:54;44728:1;44732:2;44736:7;44745:5;44697:22;:54::i;:::-;44675:154;;;;-1:-1:-1;;;44675:154:0;;;;;;;:::i;45173:439::-;-1:-1:-1;;;;;45253:16:0;;45245:61;;;;-1:-1:-1;;;45245:61:0;;26745:2:1;45245:61:0;;;26727:21:1;;;26764:18;;;26757:30;26823:34;26803:18;;;26796:62;26875:18;;45245:61:0;26543:356:1;45245:61:0;43260:4;43284:16;;;:7;:16;;;;;;-1:-1:-1;;;;;43284:16:0;:30;45317:58;;;;-1:-1:-1;;;45317:58:0;;27106:2:1;45317:58:0;;;27088:21:1;27145:2;27125:18;;;27118:30;27184;27164:18;;;27157:58;27232:18;;45317:58:0;26904:352:1;45317:58:0;45388:45;45417:1;45421:2;45425:7;45388:20;:45::i;:::-;-1:-1:-1;;;;;45446:13:0;;;;;;:9;:13;;;;;:18;;45463:1;;45446:13;:18;;45463:1;;45446:18;:::i;:::-;;;;-1:-1:-1;;45475:16:0;;;;:7;:16;;;;;;:21;;-1:-1:-1;;;;;;45475:21:0;-1:-1:-1;;;;;45475:21:0;;;;;;;;45514:33;;45475:16;;;45514:33;;45475:16;;45514:33;40234:155;;:::o;-1:-1:-1:-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:131:1;-1:-1:-1;;;;;;88:32:1;;78:43;;68:71;;135:1;132;125:12;68:71;14:131;:::o;150:245::-;208:6;261:2;249:9;240:7;236:23;232:32;229:52;;;277:1;274;267:12;229:52;316:9;303:23;335:30;359:5;335:30;:::i;592:258::-;664:1;674:113;688:6;685:1;682:13;674:113;;;764:11;;;758:18;745:11;;;738:39;710:2;703:10;674:113;;;805:6;802:1;799:13;796:48;;;-1:-1:-1;;840:1:1;822:16;;815:27;592:258::o;855:::-;897:3;935:5;929:12;962:6;957:3;950:19;978:63;1034:6;1027:4;1022:3;1018:14;1011:4;1004:5;1000:16;978:63;:::i;:::-;1095:2;1074:15;-1:-1:-1;;1070:29:1;1061:39;;;;1102:4;1057:50;;855:258;-1:-1:-1;;855:258:1:o;1118:220::-;1267:2;1256:9;1249:21;1230:4;1287:45;1328:2;1317:9;1313:18;1305:6;1287:45;:::i;1525:180::-;1584:6;1637:2;1625:9;1616:7;1612:23;1608:32;1605:52;;;1653:1;1650;1643:12;1605:52;-1:-1:-1;1676:23:1;;1525:180;-1:-1:-1;1525:180:1:o;2314:173::-;2382:20;;-1:-1:-1;;;;;2431:31:1;;2421:42;;2411:70;;2477:1;2474;2467:12;2411:70;2314:173;;;:::o;2492:254::-;2560:6;2568;2621:2;2609:9;2600:7;2596:23;2592:32;2589:52;;;2637:1;2634;2627:12;2589:52;2660:29;2679:9;2660:29;:::i;:::-;2650:39;2736:2;2721:18;;;;2708:32;;-1:-1:-1;;;2492:254:1:o;2751:328::-;2828:6;2836;2844;2897:2;2885:9;2876:7;2872:23;2868:32;2865:52;;;2913:1;2910;2903:12;2865:52;2936:29;2955:9;2936:29;:::i;:::-;2926:39;;2984:38;3018:2;3007:9;3003:18;2984:38;:::i;:::-;2974:48;;3069:2;3058:9;3054:18;3041:32;3031:42;;2751:328;;;;;:::o;3084:367::-;3147:8;3157:6;3211:3;3204:4;3196:6;3192:17;3188:27;3178:55;;3229:1;3226;3219:12;3178:55;-1:-1:-1;3252:20:1;;3295:18;3284:30;;3281:50;;;3327:1;3324;3317:12;3281:50;3364:4;3356:6;3352:17;3340:29;;3424:3;3417:4;3407:6;3404:1;3400:14;3392:6;3388:27;3384:38;3381:47;3378:67;;;3441:1;3438;3431:12;3378:67;3084:367;;;;;:::o;3456:511::-;3551:6;3559;3567;3620:2;3608:9;3599:7;3595:23;3591:32;3588:52;;;3636:1;3633;3626:12;3588:52;3676:9;3663:23;3709:18;3701:6;3698:30;3695:50;;;3741:1;3738;3731:12;3695:50;3780:70;3842:7;3833:6;3822:9;3818:22;3780:70;:::i;:::-;3869:8;;-1:-1:-1;3754:96:1;-1:-1:-1;3923:38:1;;-1:-1:-1;3957:2:1;3942:18;;3923:38;:::i;:::-;3913:48;;3456:511;;;;;:::o;3972:156::-;4038:20;;4098:4;4087:16;;4077:27;;4067:55;;4118:1;4115;4108:12;4133:594;4244:6;4252;4260;4268;4276;4284;4292;4345:3;4333:9;4324:7;4320:23;4316:33;4313:53;;;4362:1;4359;4352:12;4313:53;4398:9;4385:23;4375:33;;4455:2;4444:9;4440:18;4427:32;4417:42;;4506:2;4495:9;4491:18;4478:32;4468:42;;4557:2;4546:9;4542:18;4529:32;4519:42;;4580:37;4612:3;4601:9;4597:19;4580:37;:::i;:::-;4570:47;;4664:3;4653:9;4649:19;4636:33;4626:43;;4716:3;4705:9;4701:19;4688:33;4678:43;;4133:594;;;;;;;;;;:::o;4732:391::-;4818:6;4826;4834;4842;4895:3;4883:9;4874:7;4870:23;4866:33;4863:53;;;4912:1;4909;4902:12;4863:53;4948:9;4935:23;4925:33;;5005:2;4994:9;4990:18;4977:32;4967:42;;5056:2;5045:9;5041:18;5028:32;5018:42;;5079:38;5113:2;5102:9;5098:18;5079:38;:::i;:::-;5069:48;;4732:391;;;;;;;:::o;5954:254::-;6022:6;6030;6083:2;6071:9;6062:7;6058:23;6054:32;6051:52;;;6099:1;6096;6089:12;6051:52;6135:9;6122:23;6112:33;;6164:38;6198:2;6187:9;6183:18;6164:38;:::i;:::-;6154:48;;5954:254;;;;;:::o;6213:248::-;6281:6;6289;6342:2;6330:9;6321:7;6317:23;6313:32;6310:52;;;6358:1;6355;6348:12;6310:52;-1:-1:-1;;6381:23:1;;;6451:2;6436:18;;;6423:32;;-1:-1:-1;6213:248:1:o;6466:669::-;6586:6;6594;6602;6610;6618;6626;6634;6642;6695:3;6683:9;6674:7;6670:23;6666:33;6663:53;;;6712:1;6709;6702:12;6663:53;6748:9;6735:23;6725:33;;6805:2;6794:9;6790:18;6777:32;6767:42;;6856:2;6845:9;6841:18;6828:32;6818:42;;6879:38;6913:2;6902:9;6898:18;6879:38;:::i;:::-;6869:48;;6964:3;6953:9;6949:19;6936:33;6926:43;;6988:37;7020:3;7009:9;7005:19;6988:37;:::i;:::-;6978:47;;7072:3;7061:9;7057:19;7044:33;7034:43;;7124:3;7113:9;7109:19;7096:33;7086:43;;6466:669;;;;;;;;;;;:::o;7140:592::-;7211:6;7219;7272:2;7260:9;7251:7;7247:23;7243:32;7240:52;;;7288:1;7285;7278:12;7240:52;7328:9;7315:23;7357:18;7398:2;7390:6;7387:14;7384:34;;;7414:1;7411;7404:12;7384:34;7452:6;7441:9;7437:22;7427:32;;7497:7;7490:4;7486:2;7482:13;7478:27;7468:55;;7519:1;7516;7509:12;7468:55;7559:2;7546:16;7585:2;7577:6;7574:14;7571:34;;;7601:1;7598;7591:12;7571:34;7646:7;7641:2;7632:6;7628:2;7624:15;7620:24;7617:37;7614:57;;;7667:1;7664;7657:12;7614:57;7698:2;7690:11;;;;;7720:6;;-1:-1:-1;7140:592:1;;-1:-1:-1;;;;7140:592:1:o;7737:186::-;7796:6;7849:2;7837:9;7828:7;7824:23;7820:32;7817:52;;;7865:1;7862;7855:12;7817:52;7888:29;7907:9;7888:29;:::i;7928:717::-;8050:6;8058;8066;8074;8082;8090;8143:3;8131:9;8122:7;8118:23;8114:33;8111:53;;;8160:1;8157;8150:12;8111:53;8200:9;8187:23;8233:18;8225:6;8222:30;8219:50;;;8265:1;8262;8255:12;8219:50;8304:70;8366:7;8357:6;8346:9;8342:22;8304:70;:::i;:::-;8393:8;;-1:-1:-1;8278:96:1;-1:-1:-1;;8475:2:1;8460:18;;8447:32;;-1:-1:-1;8526:2:1;8511:18;;8498:32;;-1:-1:-1;8577:2:1;8562:18;;8549:32;;-1:-1:-1;8600:39:1;8634:3;8619:19;;8600:39;:::i;:::-;8590:49;;7928:717;;;;;;;;:::o;8903:773::-;9025:6;9033;9041;9049;9102:2;9090:9;9081:7;9077:23;9073:32;9070:52;;;9118:1;9115;9108:12;9070:52;9158:9;9145:23;9187:18;9228:2;9220:6;9217:14;9214:34;;;9244:1;9241;9234:12;9214:34;9283:70;9345:7;9336:6;9325:9;9321:22;9283:70;:::i;:::-;9372:8;;-1:-1:-1;9257:96:1;-1:-1:-1;9460:2:1;9445:18;;9432:32;;-1:-1:-1;9476:16:1;;;9473:36;;;9505:1;9502;9495:12;9473:36;;9544:72;9608:7;9597:8;9586:9;9582:24;9544:72;:::i;:::-;8903:773;;;;-1:-1:-1;9635:8:1;-1:-1:-1;;;;8903:773:1:o;9681:118::-;9767:5;9760:13;9753:21;9746:5;9743:32;9733:60;;9789:1;9786;9779:12;9804:315;9869:6;9877;9930:2;9918:9;9909:7;9905:23;9901:32;9898:52;;;9946:1;9943;9936:12;9898:52;9969:29;9988:9;9969:29;:::i;:::-;9959:39;;10048:2;10037:9;10033:18;10020:32;10061:28;10083:5;10061:28;:::i;:::-;10108:5;10098:15;;;9804:315;;;;;:::o;10124:127::-;10185:10;10180:3;10176:20;10173:1;10166:31;10216:4;10213:1;10206:15;10240:4;10237:1;10230:15;10256:1138;10351:6;10359;10367;10375;10428:3;10416:9;10407:7;10403:23;10399:33;10396:53;;;10445:1;10442;10435:12;10396:53;10468:29;10487:9;10468:29;:::i;:::-;10458:39;;10516:38;10550:2;10539:9;10535:18;10516:38;:::i;:::-;10506:48;;10601:2;10590:9;10586:18;10573:32;10563:42;;10656:2;10645:9;10641:18;10628:32;10679:18;10720:2;10712:6;10709:14;10706:34;;;10736:1;10733;10726:12;10706:34;10774:6;10763:9;10759:22;10749:32;;10819:7;10812:4;10808:2;10804:13;10800:27;10790:55;;10841:1;10838;10831:12;10790:55;10877:2;10864:16;10899:2;10895;10892:10;10889:36;;;10905:18;;:::i;:::-;10980:2;10974:9;10948:2;11034:13;;-1:-1:-1;;11030:22:1;;;11054:2;11026:31;11022:40;11010:53;;;11078:18;;;11098:22;;;11075:46;11072:72;;;11124:18;;:::i;:::-;11164:10;11160:2;11153:22;11199:2;11191:6;11184:18;11239:7;11234:2;11229;11225;11221:11;11217:20;11214:33;11211:53;;;11260:1;11257;11250:12;11211:53;11316:2;11311;11307;11303:11;11298:2;11290:6;11286:15;11273:46;11361:1;11356:2;11351;11343:6;11339:15;11335:24;11328:35;11382:6;11372:16;;;;;;;10256:1138;;;;;;;:::o;11399:460::-;11494:6;11502;11510;11518;11526;11579:3;11567:9;11558:7;11554:23;11550:33;11547:53;;;11596:1;11593;11586:12;11547:53;11632:9;11619:23;11609:33;;11689:2;11678:9;11674:18;11661:32;11651:42;;11740:2;11729:9;11725:18;11712:32;11702:42;;11791:2;11780:9;11776:18;11763:32;11753:42;;11814:39;11848:3;11837:9;11833:19;11814:39;:::i;:::-;11804:49;;11399:460;;;;;;;;:::o;11864:437::-;11950:6;11958;12011:2;11999:9;11990:7;11986:23;11982:32;11979:52;;;12027:1;12024;12017:12;11979:52;12067:9;12054:23;12100:18;12092:6;12089:30;12086:50;;;12132:1;12129;12122:12;12086:50;12171:70;12233:7;12224:6;12213:9;12209:22;12171:70;:::i;:::-;12260:8;;12145:96;;-1:-1:-1;11864:437:1;-1:-1:-1;;;;11864:437:1:o;12306:260::-;12374:6;12382;12435:2;12423:9;12414:7;12410:23;12406:32;12403:52;;;12451:1;12448;12441:12;12403:52;12474:29;12493:9;12474:29;:::i;:::-;12464:39;;12522:38;12556:2;12545:9;12541:18;12522:38;:::i;12571:380::-;12650:1;12646:12;;;;12693;;;12714:61;;12768:4;12760:6;12756:17;12746:27;;12714:61;12821:2;12813:6;12810:14;12790:18;12787:38;12784:161;;;12867:10;12862:3;12858:20;12855:1;12848:31;12902:4;12899:1;12892:15;12930:4;12927:1;12920:15;12784:161;;12571:380;;;:::o;14196:413::-;14398:2;14380:21;;;14437:2;14417:18;;;14410:30;14476:34;14471:2;14456:18;;14449:62;-1:-1:-1;;;14542:2:1;14527:18;;14520:47;14599:3;14584:19;;14196:413::o;14893:245::-;14960:6;15013:2;15001:9;14992:7;14988:23;14984:32;14981:52;;;15029:1;15026;15019:12;14981:52;15061:9;15055:16;15080:28;15102:5;15080:28;:::i;15555:127::-;15616:10;15611:3;15607:20;15604:1;15597:31;15647:4;15644:1;15637:15;15671:4;15668:1;15661:15;15687:135;15726:3;-1:-1:-1;;15747:17:1;;15744:43;;;15767:18;;:::i;:::-;-1:-1:-1;15814:1:1;15803:13;;15687:135::o;16393:439::-;16580:3;16618:6;16612:13;16634:53;16680:6;16675:3;16668:4;16660:6;16656:17;16634:53;:::i;:::-;16709:16;;;;16734:21;;;-1:-1:-1;16782:4:1;16771:16;;16764:32;16823:2;16812:14;;16393:439;-1:-1:-1;16393:439:1:o;17653:127::-;17714:10;17709:3;17705:20;17702:1;17695:31;17745:4;17742:1;17735:15;17769:4;17766:1;17759:15;18460:926;18569:4;18598:2;18627;18616:9;18609:21;18650:1;18683:6;18677:13;18713:36;18739:9;18713:36;:::i;:::-;18785:6;18780:2;18769:9;18765:18;18758:34;18811:2;18832:1;18864:2;18853:9;18849:18;18881:1;18876:121;;;;19011:1;19006:354;;;;18842:518;;18876:121;-1:-1:-1;;18924:24:1;;18904:18;;;18897:52;18984:2;18969:18;;;-1:-1:-1;18876:121:1;;19006:354;19037:6;19034:1;19027:17;19085:2;19082:1;19072:16;19110:1;19124:180;19138:6;19135:1;19132:13;19124:180;;;19231:14;;19207:17;;;19203:26;;19196:50;19274:16;;;;19153:10;;19124:180;;;19328:17;;19324:26;;;-1:-1:-1;;18842:518:1;-1:-1:-1;19377:3:1;;18460:926;-1:-1:-1;;;;;;;;18460:926:1:o;20212:168::-;20252:7;20318:1;20314;20310:6;20306:14;20303:1;20300:21;20295:1;20288:9;20281:17;20277:45;20274:71;;;20325:18;;:::i;:::-;-1:-1:-1;20365:9:1;;20212:168::o;20385:127::-;20446:10;20441:3;20437:20;20434:1;20427:31;20477:4;20474:1;20467:15;20501:4;20498:1;20491:15;20517:120;20557:1;20583;20573:35;;20588:18;;:::i;:::-;-1:-1:-1;20622:9:1;;20517:120::o;20642:693::-;20692:3;20733:5;20727:12;20762:36;20788:9;20762:36;:::i;:::-;20817:1;20834:18;;;20861:104;;;;20979:1;20974:355;;;;20827:502;;20861:104;-1:-1:-1;;20894:24:1;;20882:37;;20939:16;;;;-1:-1:-1;20861:104:1;;20974:355;21005:5;21002:1;20995:16;21034:4;21079:2;21076:1;21066:16;21104:1;21118:165;21132:6;21129:1;21126:13;21118:165;;;21210:14;;21197:11;;;21190:35;21253:16;;;;21147:10;;21118:165;;;21122:3;;;21312:6;21307:3;21303:16;21296:23;;20827:502;;;;;20642:693;;;;:::o;21340:376::-;21516:3;21544:38;21578:3;21570:6;21544:38;:::i;:::-;21611:6;21605:13;21627:52;21672:6;21668:2;21661:4;21653:6;21649:17;21627:52;:::i;:::-;21695:15;;21340:376;-1:-1:-1;;;;21340:376:1:o;21721:125::-;21761:4;21789:1;21786;21783:8;21780:34;;;21794:18;;:::i;:::-;-1:-1:-1;21831:9:1;;21721:125::o;21851:128::-;21891:3;21922:1;21918:6;21915:1;21912:13;21909:39;;;21928:18;;:::i;:::-;-1:-1:-1;21964:9:1;;21851:128::o;21984:632::-;22229:2;22211:21;;;22248:18;;22241:34;;;-1:-1:-1;;;;;;22287:31:1;;22284:51;;;22331:1;22328;22321:12;22284:51;22365:6;22362:1;22358:14;22423:6;22415;22409:3;22398:9;22394:19;22381:49;22501:1;22453:22;;;22477:3;22449:32;22490:13;;;22553:4;22538:20;;22531:36;;;;-1:-1:-1;22598:2:1;22583:18;22576:34;22449:32;21984:632;-1:-1:-1;;21984:632:1:o;22621:354::-;22850:3;22878:38;22912:3;22904:6;22878:38;:::i;:::-;-1:-1:-1;;;22925:18:1;;22967:1;22959:10;;22621:354;-1:-1:-1;;;22621:354:1:o;24204:184::-;24274:6;24327:2;24315:9;24306:7;24302:23;24298:32;24295:52;;;24343:1;24340;24333:12;24295:52;-1:-1:-1;24366:16:1;;24204:184;-1:-1:-1;24204:184:1:o;25127:414::-;25329:2;25311:21;;;25368:2;25348:18;;;25341:30;25407:34;25402:2;25387:18;;25380:62;-1:-1:-1;;;25473:2:1;25458:18;;25451:48;25531:3;25516:19;;25127:414::o;25546:112::-;25578:1;25604;25594:35;;25609:18;;:::i;:::-;-1:-1:-1;25643:9:1;;25546:112::o;25663:489::-;-1:-1:-1;;;;;25932:15:1;;;25914:34;;25984:15;;25979:2;25964:18;;25957:43;26031:2;26016:18;;26009:34;;;26079:3;26074:2;26059:18;;26052:31;;;25857:4;;26100:46;;26126:19;;26118:6;26100:46;:::i;:::-;26092:54;25663:489;-1:-1:-1;;;;;;25663:489:1:o;26157:249::-;26226:6;26279:2;26267:9;26258:7;26254:23;26250:32;26247:52;;;26295:1;26292;26285:12;26247:52;26327:9;26321:16;26346:30;26370:5;26346:30;:::i;26411:127::-;26472:10;26467:3;26463:20;26460:1;26453:31;26503:4;26500:1;26493:15;26527:4;26524:1;26517:15

Swarm Source

ipfs://08f44c4f44406741d7a1d635245021e57f69f96beed3fe60c42db712ac1b072f
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.