ETH Price: $3,157.67 (+1.23%)
Gas: 2 Gwei

Token

Staked Drift (stDRIFT)
 

Overview

Max Total Supply

256,124,596.536758491051082258 stDRIFT

Holders

206

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
406,221.000000323967050657 stDRIFT

Value
$0.00
0x03e1c7eb22b57a271f8e442d6c6eb9dfd5890d34
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:
StakeDriftToken

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, Apache-2.0 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2024-04-25
*/

// File: @openzeppelin/contracts/utils/structs/EnumerableSet.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```solidity
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._positions[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._positions[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

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


// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol)
pragma solidity ^0.8.20;

/**
 * @dev Provides tracking nonces for addresses. Nonces will only increment.
 */
abstract contract Nonces {
    /**
     * @dev The nonce used for an `account` is not the expected current nonce.
     */
    error InvalidAccountNonce(address account, uint256 currentNonce);

    mapping(address account => uint256) private _nonces;

    /**
     * @dev Returns the next unused nonce for an address.
     */
    function nonces(address owner) public view virtual returns (uint256) {
        return _nonces[owner];
    }

    /**
     * @dev Consumes a nonce.
     *
     * Returns the current value and increments nonce.
     */
    function _useNonce(address owner) internal virtual returns (uint256) {
        // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be
        // decremented or reset. This guarantees that the nonce never overflows.
        unchecked {
            // It is important to do x++ and not ++x here.
            return _nonces[owner]++;
        }
    }

    /**
     * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`.
     */
    function _useCheckedNonce(address owner, uint256 nonce) internal virtual {
        uint256 current = _useNonce(owner);
        if (nonce != current) {
            revert InvalidAccountNonce(owner, current);
        }
    }
}

// File: @openzeppelin/contracts/interfaces/IERC5267.sol


// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

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


// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

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


// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;


// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using
     * {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}

// File: @openzeppelin/contracts/utils/math/SignedMath.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

// File: @openzeppelin/contracts/utils/math/Math.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

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

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

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

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

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
     * denominator == 0.
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
     * Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
            // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
            // works in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

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


// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)

pragma solidity ^0.8.20;



/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant HEX_DIGITS = "0123456789abcdef";
    uint8 private constant ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        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_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
     * representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

// File: @openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol)

pragma solidity ^0.8.20;


/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

// File: @openzeppelin/contracts/utils/cryptography/EIP712.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;




/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}

// File: @openzeppelin/contracts/utils/cryptography/ECDSA.sol


// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
     * return address(0) without also returning an error description. Errors are documented using an enum (error type)
     * and a bytes32 providing additional information about the error.
     *
     * If no error is returned, then the address can be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// File: @openzeppelin/contracts/interfaces/draft-IERC6093.sol


// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

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


// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol


// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;


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

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

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

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

// File: utils/AllowableAddress.sol


pragma solidity ^0.8.4;



contract AllowableAddress is Ownable {
    using EnumerableSet for EnumerableSet.AddressSet;

    // @dev the allowed minter addresses
    EnumerableSet.AddressSet internal s_minters;
    // @dev the allowed burner addresses
    EnumerableSet.AddressSet internal s_burners;

    /******* Variables *******/
    // blacklist address => bool
    mapping(address => bool) internal blacklistAddress;

    /******* Modifiers *******/
    modifier blacklistCheck(address _from, address _to) {
        require(
            !blacklistAddress[_from] && !blacklistAddress[_to],
            "Address is blacklisted"
        );
        _;
    }

    modifier onlyMinter() {
        if (!isMinter(msg.sender)) revert SenderNotMinter(msg.sender);
        _;
    }

    modifier onlyBurner() {
        if (!isBurner(msg.sender)) revert SenderNotBurner(msg.sender);
        _;
    }

    /******* Events *******/
    error SenderNotMinter(address sender);
    error SenderNotBurner(address sender);
    error MaxSupplyExceeded(uint256 supplyAfterMint);

    event MintAccessGranted(address indexed minter);
    event BurnAccessGranted(address indexed burner);
    event MintAccessRevoked(address indexed minter);
    event BurnAccessRevoked(address indexed burner);
    event BlacklistUpdated(bool status);

    /******* Constructor *******/
    constructor(address _ownerAddress) Ownable(_ownerAddress) {}

    /*
     * @notice Manage blacklisting to restrict addresses
     * @param addresses     Array of addresses
     * @param status        If blacklist passing true, false otherwise.
     */
    function manageBlacklist(address[] calldata addresses, bool status)
        external
        virtual
        onlyOwner
    {
        for (uint256 i; i < addresses.length; ++i) {
            blacklistAddress[addresses[i]] = status;
        }
        emit BlacklistUpdated(status);
    }

    /*
     * @notice grants both mint and burn roles to `burnAndMinter`.
     * @notice Accessable to only owner.
     * @param burnAndMinter      Any address for mint and burn access
     */
    function grantMintAndBurnRoles(address burnAndMinter) external onlyOwner {
        grantMintRole(burnAndMinter);
        grantBurnRole(burnAndMinter);
    }

    /*
     * @notice Grants mint role to the given address.
     * @notice Accessable to only owner.
     * @param minter    Any address for mint access
     */
    function grantMintRole(address minter) public onlyOwner {
        if (s_minters.add(minter)) {
            emit MintAccessGranted(minter);
        }
    }

    /*
     * @notice Grants burn role to the given address.
     * @notice Accessable to only owner.
     * @param burner    Any address for burn access
     */
    function grantBurnRole(address burner) public onlyOwner {
        if (s_burners.add(burner)) {
            emit BurnAccessGranted(burner);
        }
    }

    /*
     * @notice Revokes mint role for the given address.
     * @notice Accessable to only owner.
     * @param minter    Any address for remove mint access
     */
    function revokeMintRole(address minter) public onlyOwner {
        if (s_minters.remove(minter)) {
            emit MintAccessRevoked(minter);
        }
    }

    /*
     * @notice Revokes burn role from the given address.
     * @notice Accessable to only owner
     * @param burner    Any address for remove burn access
     */
    function revokeBurnRole(address burner) public onlyOwner {
        if (s_burners.remove(burner)) {
            emit BurnAccessRevoked(burner);
        }
    }

    /*
     * @param _address      Any address
     * @return {the address is blacklisted or not}.
     */
    function isBlacklisted(address _address) public view returns (bool) {
        return blacklistAddress[_address];
    }

    /*
     * @return {all permissioned minters}
     */
    function getMinters() public view returns (address[] memory) {
        return s_minters.values();
    }

    /*
     * @return {all permissioned burners}
     */
    function getBurners() public view returns (address[] memory) {
        return s_burners.values();
    }

    /*
     * @notice Checks whether a given address is a minter for this token.
     * @return {true if the address is allowed to mint}.
     */
    function isMinter(address minter) public view returns (bool) {
        return s_minters.contains(minter);
    }

    /*
     * @notice Checks whether a given address is a burner for this token.
     * @return {true if the address is allowed to burn}.
     */
    function isBurner(address burner) public view returns (bool) {
        return s_burners.contains(burner);
    }
}

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


// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;


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

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

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

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

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

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

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

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

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

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

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

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


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

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

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

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

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

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

// File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;


/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

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


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;





/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

// File: @openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)

pragma solidity ^0.8.20;






/**
 * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
    bytes32 private constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /**
     * @dev Permit deadline has expired.
     */
    error ERC2612ExpiredSignature(uint256 deadline);

    /**
     * @dev Mismatched signature.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
     */
    constructor(string memory name) EIP712(name, "1") {}

    /**
     * @inheritdoc IERC20Permit
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        if (block.timestamp > deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        if (signer != owner) {
            revert ERC2612InvalidSigner(signer, owner);
        }

        _approve(owner, spender, value);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
        return super.nonces(owner);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
        return _domainSeparatorV4();
    }
}

// File: @openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol)

pragma solidity ^0.8.20;



/**
 * @dev ERC20 token with pausable token transfers, minting and burning.
 *
 * Useful for scenarios such as preventing trades until the end of an evaluation
 * period, or having an emergency switch for freezing all token transfers in the
 * event of a large bug.
 *
 * IMPORTANT: This contract does not include public pause and unpause functions. In
 * addition to inheriting this contract, you must define both functions, invoking the
 * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
 * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
 * make the contract pause mechanism of the contract unreachable, and thus unusable.
 */
abstract contract ERC20Pausable is ERC20, Pausable {
    /**
     * @dev See {ERC20-_update}.
     *
     * Requirements:
     *
     * - the contract must not be paused.
     */
    function _update(address from, address to, uint256 value) internal virtual override whenNotPaused {
        super._update(from, to, value);
    }
}

// File: @openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol


// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.20;



/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, deducting from
     * the caller's allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `value`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

// File: StakeDriftToken.sol

/**
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) 2024, DRIFTToken.
 *
 * DRIFT is the studio token behind the Drift studio. Drift is a Web3 game studio, which already has a ready-to-play Beta version of its game, Payout Pursuit.
 *
 * The DRIFT token has utility for gamers and non-gamers. Gamers that hold DRIFT will be able to customize their gaming experience with NFT skins and other features.
 * Non-gamers who stake DRIFT receive a percentage of game revenue, and the token also receives Liquidity from a percentage of game revenue.
 *
 * The Drift project has been developed by a highly experienced, fully doxxed Web3 team, with multiple successes in the Web3 space.
 *
 * Drift:
 * https://drifttoken.io/
 *
 * Influ3nce:
 * https://influ3nce.me/
 *
 * Amba$$ador:
 * https://influ3nce.me/ambassador/
 *
 * Twitter / X:
 * https://twitter.com/TheDriftToken
 *
 * Telegram:
 * https://t.me/driftportal
 *
 */

pragma solidity 0.8.20;






contract StakeDriftToken is
    ERC20,
    ERC20Burnable,
    ERC20Pausable,
    ERC20Permit,
    AllowableAddress
{
    constructor(address _ownerAddress)
        AllowableAddress(_ownerAddress)
        ERC20("Staked Drift", "stDRIFT")
        ERC20Permit("Staked Drift")
    {
        grantMintRole(_ownerAddress);
        grantBurnRole(_ownerAddress);
    }

    function mint(address to, uint256 amount) public onlyMinter {
        _mint(to, amount);
    }

    function burn(uint256 value) public override onlyBurner {
        super.burn(value);
    }

    function burnFrom(address account, uint256 value)
        public
        override
        onlyBurner
    {
        super.burnFrom(account, value);
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function transfer(address to, uint256 value)
        public
        virtual
        override
        blacklistCheck(_msgSender(), to)
        returns (bool)
    {
        super.transfer(to, value);
        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 value
    ) public virtual override blacklistCheck(from, to) returns (bool) {
        super.transferFrom(from, to, value);
        return true;
    }

    function _update(
        address from,
        address to,
        uint256 value
    ) internal override(ERC20, ERC20Pausable) {
        super._update(from, to, value);
    }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_ownerAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"ERC2612ExpiredSignature","type":"error"},{"inputs":[{"internalType":"address","name":"signer","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC2612InvalidSigner","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[{"internalType":"uint256","name":"supplyAfterMint","type":"uint256"}],"name":"MaxSupplyExceeded","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotBurner","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"SenderNotMinter","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"BlacklistUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burner","type":"address"}],"name":"BurnAccessGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burner","type":"address"}],"name":"BurnAccessRevoked","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"}],"name":"MintAccessGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"}],"name":"MintAccessRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBurners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinters","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"burner","type":"address"}],"name":"grantBurnRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"burnAndMinter","type":"address"}],"name":"grantMintAndBurnRoles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"grantMintRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"burner","type":"address"}],"name":"isBurner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"bool","name":"status","type":"bool"}],"name":"manageBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","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":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"burner","type":"address"}],"name":"revokeBurnRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"revokeMintRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]

61016060405234801562000011575f80fd5b5060405162003ce838038062003ce883398181016040528101906200003791906200077a565b80806040518060400160405280600c81526020017f5374616b65642044726966740000000000000000000000000000000000000000815250806040518060400160405280600181526020017f31000000000000000000000000000000000000000000000000000000000000008152506040518060400160405280600c81526020017f5374616b656420447269667400000000000000000000000000000000000000008152506040518060400160405280600781526020017f7374445249465400000000000000000000000000000000000000000000000000815250816003908162000123919062000a0e565b50806004908162000135919062000a0e565b5050505f60055f6101000a81548160ff02191690831515021790555062000167600683620002b160201b90919060201c565b610120818152505062000185600782620002b160201b90919060201c565b6101408181525050818051906020012060e08181525050808051906020012061010081815250504660a08181525050620001c46200030660201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160362000275575f6040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016200026c919062000b03565b60405180910390fd5b62000286816200036260201b60201c565b505062000299816200042560201b60201c565b620002aa816200049860201b60201c565b5062000cee565b5f602083511015620002d657620002ce836200050b60201b60201c565b905062000300565b82620002e8836200057560201b60201c565b5f019081620002f8919062000a0e565b5060ff5f1b90505b92915050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60e0516101005146306040516020016200034795949392919062000b49565b60405160208183030381529060405280519060200120905090565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b620004356200057e60201b60201c565b6200044b81600a6200062060201b90919060201c565b1562000495578073ffffffffffffffffffffffffffffffffffffffff167fe46fef8bbff1389d9010703cf8ebb363fb3daf5bf56edc27080b67bc8d9251ea60405160405180910390a25b50565b620004a86200057e60201b60201c565b620004be81600c6200062060201b90919060201c565b1562000508578073ffffffffffffffffffffffffffffffffffffffff167f92308bb7573b2a3d17ddb868b39d8ebec433f3194421abc22d084f89658c9bad60405160405180910390a25b50565b5f80829050601f815111156200055a57826040517f305a27a900000000000000000000000000000000000000000000000000000000815260040162000551919062000c2e565b60405180910390fd5b805181620005689062000c7f565b5f1c175f1b915050919050565b5f819050919050565b6200058e6200065560201b60201c565b73ffffffffffffffffffffffffffffffffffffffff16620005b46200065c60201b60201c565b73ffffffffffffffffffffffffffffffffffffffff16146200061e57620005e06200065560201b60201c565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040162000615919062000b03565b60405180910390fd5b565b5f6200064d835f018373ffffffffffffffffffffffffffffffffffffffff165f1b6200068460201b60201c565b905092915050565b5f33905090565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f620006978383620006f560201b60201c565b620006eb57825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050620006ef565b5f90505b92915050565b5f80836001015f8481526020019081526020015f20541415905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f620007448262000719565b9050919050565b620007568162000738565b811462000761575f80fd5b50565b5f8151905062000774816200074b565b92915050565b5f6020828403121562000792576200079162000715565b5b5f620007a18482850162000764565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200082657607f821691505b6020821081036200083c576200083b620007e1565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620008a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8262000863565b620008ac868362000863565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620008f6620008f0620008ea84620008c4565b620008cd565b620008c4565b9050919050565b5f819050919050565b6200091183620008d6565b620009296200092082620008fd565b8484546200086f565b825550505050565b5f90565b6200093f62000931565b6200094c81848462000906565b505050565b5b818110156200097357620009675f8262000935565b60018101905062000952565b5050565b601f821115620009c2576200098c8162000842565b620009978462000854565b81016020851015620009a7578190505b620009bf620009b68562000854565b83018262000951565b50505b505050565b5f82821c905092915050565b5f620009e45f1984600802620009c7565b1980831691505092915050565b5f620009fe8383620009d3565b9150826002028217905092915050565b62000a1982620007aa565b67ffffffffffffffff81111562000a355762000a34620007b4565b5b62000a4182546200080e565b62000a4e82828562000977565b5f60209050601f83116001811462000a84575f841562000a6f578287015190505b62000a7b8582620009f1565b86555062000aea565b601f19841662000a948662000842565b5f5b8281101562000abd5784890151825560018201915060208501945060208101905062000a96565b8683101562000add578489015162000ad9601f891682620009d3565b8355505b6001600288020188555050505b505050505050565b62000afd8162000738565b82525050565b5f60208201905062000b185f83018462000af2565b92915050565b5f819050919050565b62000b328162000b1e565b82525050565b62000b4381620008c4565b82525050565b5f60a08201905062000b5e5f83018862000b27565b62000b6d602083018762000b27565b62000b7c604083018662000b27565b62000b8b606083018562000b38565b62000b9a608083018462000af2565b9695505050505050565b5f82825260208201905092915050565b5f5b8381101562000bd357808201518184015260208101905062000bb6565b5f8484015250505050565b5f601f19601f8301169050919050565b5f62000bfa82620007aa565b62000c06818562000ba4565b935062000c1881856020860162000bb4565b62000c238162000bde565b840191505092915050565b5f6020820190508181035f83015262000c48818462000bee565b905092915050565b5f81519050919050565b5f819050602082019050919050565b5f62000c76825162000b1e565b80915050919050565b5f62000c8b8262000c50565b8262000c978462000c5a565b905062000ca48162000c69565b9250602082101562000ce75762000ce27fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080262000863565b831692505b5050919050565b60805160a05160c05160e051610100516101205161014051612fa862000d405f395f61165001525f61161501525f611b0101525f611ae001525f6111da01525f61123001525f6112590152612fa85ff3fe608060405234801561000f575f80fd5b50600436106101f9575f3560e01c80637ecebe0011610118578063c2e3273d116100ab578063dd62ed3e1161007a578063dd62ed3e1461057d578063f2fde38b146105ad578063f81094f3146105c9578063fb2f3492146105e5578063fe575a8714610601576101f9565b8063c2e3273d1461050d578063c630948d14610529578063c64d0ebc14610545578063d505accf14610561576101f9565b80638da5cb5b116100e75780638da5cb5b1461047157806395d89b411461048f578063a9059cbb146104ad578063aa271e1a146104dd576101f9565b80637ecebe00146103f55780638456cb591461042557806384b0196e1461042f57806386fe8b4314610453576101f9565b806342966c68116101905780636b32810b1161015f5780636b32810b1461038157806370a082311461039f578063715018a6146103cf57806379cc6790146103d9576101f9565b806342966c68146102fb5780634334614a146103175780634f5632f8146103475780635c975abb14610363576101f9565b8063313ce567116101cc578063313ce567146102995780633644e515146102b75780633f4ba83a146102d557806340c10f19146102df576101f9565b806306fdde03146101fd578063095ea7b31461021b57806318160ddd1461024b57806323b872dd14610269575b5f80fd5b610205610631565b60405161021291906124ee565b60405180910390f35b610235600480360381019061023091906125a3565b6106c1565b60405161024291906125fb565b60405180910390f35b6102536106e3565b6040516102609190612623565b60405180910390f35b610283600480360381019061027e919061263c565b6106ec565b60405161029091906125fb565b60405180910390f35b6102a16107e5565b6040516102ae91906126a7565b60405180910390f35b6102bf6107ed565b6040516102cc91906126d8565b60405180910390f35b6102dd6107fb565b005b6102f960048036038101906102f491906125a3565b61080d565b005b610315600480360381019061031091906126f1565b610865565b005b610331600480360381019061032c919061271c565b6108bb565b60405161033e91906125fb565b60405180910390f35b610361600480360381019061035c919061271c565b6108d7565b005b61036b61093f565b60405161037891906125fb565b60405180910390f35b610389610954565b60405161039691906127fe565b60405180910390f35b6103b960048036038101906103b4919061271c565b610965565b6040516103c69190612623565b60405180910390f35b6103d76109aa565b005b6103f360048036038101906103ee91906125a3565b6109bd565b005b61040f600480360381019061040a919061271c565b610a15565b60405161041c9190612623565b60405180910390f35b61042d610a26565b005b610437610a38565b60405161044a979695949392919061291e565b60405180910390f35b61045b610add565b60405161046891906127fe565b60405180910390f35b610479610aee565b60405161048691906129a0565b60405180910390f35b610497610b16565b6040516104a491906124ee565b60405180910390f35b6104c760048036038101906104c291906125a3565b610ba6565b6040516104d491906125fb565b60405180910390f35b6104f760048036038101906104f2919061271c565b610ca4565b60405161050491906125fb565b60405180910390f35b6105276004803603810190610522919061271c565b610cc0565b005b610543600480360381019061053e919061271c565b610d28565b005b61055f600480360381019061055a919061271c565b610d45565b005b61057b60048036038101906105769190612a0d565b610dad565b005b61059760048036038101906105929190612aaa565b610ef2565b6040516105a49190612623565b60405180910390f35b6105c760048036038101906105c2919061271c565b610f74565b005b6105e360048036038101906105de919061271c565b610ff8565b005b6105ff60048036038101906105fa9190612b73565b611060565b005b61061b6004803603810190610616919061271c565b61113e565b60405161062891906125fb565b60405180910390f35b60606003805461064090612bfd565b80601f016020809104026020016040519081016040528092919081815260200182805461066c90612bfd565b80156106b75780601f1061068e576101008083540402835291602001916106b7565b820191905f5260205f20905b81548152906001019060200180831161069a57829003601f168201915b5050505050905090565b5f806106cb611190565b90506106d8818585611197565b600191505092915050565b5f600254905090565b5f8383600e5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615801561078d5750600e5f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16155b6107cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c390612c77565b60405180910390fd5b6107d78686866111a9565b506001925050509392505050565b5f6012905090565b5f6107f66111d7565b905090565b61080361128d565b61080b611314565b565b61081633610ca4565b61085757336040517fe2c8c9d500000000000000000000000000000000000000000000000000000000815260040161084e91906129a0565b60405180910390fd5b6108618282611375565b5050565b61086e336108bb565b6108af57336040517fc820b10b0000000000000000000000000000000000000000000000000000000081526004016108a691906129a0565b60405180910390fd5b6108b8816113f4565b50565b5f6108d082600c61140890919063ffffffff16565b9050919050565b6108df61128d565b6108f381600c61143590919063ffffffff16565b1561093c578073ffffffffffffffffffffffffffffffffffffffff167f0a675452746933cefe3d74182e78db7afe57ba60eaa4234b5d85e9aa41b0610c60405160405180910390a25b50565b5f60055f9054906101000a900460ff16905090565b6060610960600a611462565b905090565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6109b261128d565b6109bb5f611481565b565b6109c6336108bb565b610a0757336040517fc820b10b0000000000000000000000000000000000000000000000000000000081526004016109fe91906129a0565b60405180910390fd5b610a118282611544565b5050565b5f610a1f82611564565b9050919050565b610a2e61128d565b610a366115aa565b565b5f6060805f805f6060610a4961160c565b610a51611647565b46305f801b5f67ffffffffffffffff811115610a7057610a6f612c95565b5b604051908082528060200260200182016040528015610a9e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6060610ae9600c611462565b905090565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060048054610b2590612bfd565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5190612bfd565b8015610b9c5780601f10610b7357610100808354040283529160200191610b9c565b820191905f5260205f20905b815481529060010190602001808311610b7f57829003601f168201915b5050505050905090565b5f610baf611190565b83600e5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16158015610c4e5750600e5f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16155b610c8d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8490612c77565b60405180910390fd5b610c978585611682565b5060019250505092915050565b5f610cb982600a61140890919063ffffffff16565b9050919050565b610cc861128d565b610cdc81600a6116a490919063ffffffff16565b15610d25578073ffffffffffffffffffffffffffffffffffffffff167fe46fef8bbff1389d9010703cf8ebb363fb3daf5bf56edc27080b67bc8d9251ea60405160405180910390a25b50565b610d3061128d565b610d3981610cc0565b610d4281610d45565b50565b610d4d61128d565b610d6181600c6116a490919063ffffffff16565b15610daa578073ffffffffffffffffffffffffffffffffffffffff167f92308bb7573b2a3d17ddb868b39d8ebec433f3194421abc22d084f89658c9bad60405160405180910390a25b50565b83421115610df257836040517f62791302000000000000000000000000000000000000000000000000000000008152600401610de99190612623565b60405180910390fd5b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e208c6116d1565b89604051602001610e3696959493929190612cc2565b6040516020818303038152906040528051906020012090505f610e5882611724565b90505f610e678287878761173d565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610edb57808a6040517f4b800e46000000000000000000000000000000000000000000000000000000008152600401610ed2929190612d21565b60405180910390fd5b610ee68a8a8a611197565b50505050505050505050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b610f7c61128d565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610fec575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610fe391906129a0565b60405180910390fd5b610ff581611481565b50565b61100061128d565b61101481600a61143590919063ffffffff16565b1561105d578073ffffffffffffffffffffffffffffffffffffffff167fed998b960f6340d045f620c119730f7aa7995e7425c2401d3a5b64ff998a59e960405160405180910390a25b50565b61106861128d565b5f5b838390508110156111015781600e5f86868581811061108c5761108b612d48565b5b90506020020160208101906110a1919061271c565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff021916908315150217905550806110fa90612da2565b905061106a565b507f7dc357bd865f9219c544a8b0b14cb1583b26e3ffe765b3396ef2051d81a8de568160405161113191906125fb565b60405180910390a1505050565b5f600e5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff169050919050565b5f33905090565b6111a4838383600161176b565b505050565b5f806111b3611190565b90506111c085828561193a565b6111cb8585856119cc565b60019150509392505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561125257507f000000000000000000000000000000000000000000000000000000000000000046145b1561127f577f0000000000000000000000000000000000000000000000000000000000000000905061128a565b611287611abc565b90505b90565b611295611190565b73ffffffffffffffffffffffffffffffffffffffff166112b3610aee565b73ffffffffffffffffffffffffffffffffffffffff1614611312576112d6611190565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161130991906129a0565b60405180910390fd5b565b61131c611b51565b5f60055f6101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61135e611190565b60405161136b91906129a0565b60405180910390a1565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036113e5575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016113dc91906129a0565b60405180910390fd5b6113f05f8383611b91565b5050565b6114056113ff611190565b82611ba1565b50565b5f61142d835f018373ffffffffffffffffffffffffffffffffffffffff165f1b611c20565b905092915050565b5f61145a835f018373ffffffffffffffffffffffffffffffffffffffff165f1b611c40565b905092915050565b60605f611470835f01611d3c565b905060608190508092505050919050565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b61155682611550611190565b8361193a565b6115608282611ba1565b5050565b5f60085f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6115b2611d95565b600160055f6101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115f5611190565b60405161160291906129a0565b60405180910390a1565b606061164260067f0000000000000000000000000000000000000000000000000000000000000000611dd690919063ffffffff16565b905090565b606061167d60077f0000000000000000000000000000000000000000000000000000000000000000611dd690919063ffffffff16565b905090565b5f8061168c611190565b90506116998185856119cc565b600191505092915050565b5f6116c9835f018373ffffffffffffffffffffffffffffffffffffffff165f1b611e83565b905092915050565b5f60085f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815480929190600101919050559050919050565b5f6117366117306111d7565b83611eea565b9050919050565b5f805f8061174d88888888611f2a565b92509250925061175d8282612011565b829350505050949350505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036117db575f6040517fe602df050000000000000000000000000000000000000000000000000000000081526004016117d291906129a0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361184b575f6040517f94280d6200000000000000000000000000000000000000000000000000000000815260040161184291906129a0565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015611934578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161192b9190612623565b60405180910390a35b50505050565b5f6119458484610ef2565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146119c657818110156119b7578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016119ae93929190612de9565b60405180910390fd5b6119c584848484035f61176b565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611a3c575f6040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600401611a3391906129a0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611aac575f6040517fec442f05000000000000000000000000000000000000000000000000000000008152600401611aa391906129a0565b60405180910390fd5b611ab7838383611b91565b505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000004630604051602001611b36959493929190612e1e565b60405160208183030381529060405280519060200120905090565b611b5961093f565b611b8f576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b611b9c838383612173565b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611c11575f6040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600401611c0891906129a0565b60405180910390fd5b611c1c825f83611b91565b5050565b5f80836001015f8481526020019081526020015f20541415905092915050565b5f80836001015f8481526020019081526020015f205490505f8114611d31575f600182611c6d9190612e6f565b90505f6001865f0180549050611c839190612e6f565b9050808214611ce9575f865f018281548110611ca257611ca1612d48565b5b905f5260205f200154905080875f018481548110611cc357611cc2612d48565b5b905f5260205f20018190555083876001015f8381526020019081526020015f2081905550505b855f01805480611cfc57611cfb612ea2565b5b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050611d36565b5f9150505b92915050565b6060815f01805480602002602001604051908101604052809291908181526020018280548015611d8957602002820191905f5260205f20905b815481526020019060010190808311611d75575b50505050509050919050565b611d9d61093f565b15611dd4576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b606060ff5f1b8314611df257611deb8361218b565b9050611e7d565b818054611dfe90612bfd565b80601f0160208091040260200160405190810160405280929190818152602001828054611e2a90612bfd565b8015611e755780601f10611e4c57610100808354040283529160200191611e75565b820191905f5260205f20905b815481529060010190602001808311611e5857829003601f168201915b505050505090505b92915050565b5f611e8e8383611c20565b611ee057825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050611ee4565b5f90505b92915050565b5f6040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b5f805f7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0845f1c1115611f66575f600385925092509250612007565b5f6001888888886040515f8152602001604052604051611f899493929190612ecf565b6020604051602081039080840390855afa158015611fa9573d5f803e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ffa575f60015f801b93509350935050612007565b805f805f1b935093509350505b9450945094915050565b5f600381111561202457612023612f12565b5b82600381111561203757612036612f12565b5b031561216f576001600381111561205157612050612f12565b5b82600381111561206457612063612f12565b5b0361209b576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156120af576120ae612f12565b5b8260038111156120c2576120c1612f12565b5b0361210657805f1c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016120fd9190612623565b60405180910390fd5b60038081111561211957612118612f12565b5b82600381111561212c5761212b612f12565b5b0361216e57806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161216591906126d8565b60405180910390fd5b5b5050565b61217b611d95565b6121868383836121fd565b505050565b60605f61219783612416565b90505f602067ffffffffffffffff8111156121b5576121b4612c95565b5b6040519080825280601f01601f1916602001820160405280156121e75781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361224d578060025f8282546122419190612f3f565b9250508190555061231b565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050818110156122d6578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016122cd93929190612de9565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612362578060025f82825403925050819055506123ac565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516124099190612623565b60405180910390a3505050565b5f8060ff835f1c169050601f81111561245b576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561249b578082015181840152602081019050612480565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6124c082612464565b6124ca818561246e565b93506124da81856020860161247e565b6124e3816124a6565b840191505092915050565b5f6020820190508181035f83015261250681846124b6565b905092915050565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61253f82612516565b9050919050565b61254f81612535565b8114612559575f80fd5b50565b5f8135905061256a81612546565b92915050565b5f819050919050565b61258281612570565b811461258c575f80fd5b50565b5f8135905061259d81612579565b92915050565b5f80604083850312156125b9576125b861250e565b5b5f6125c68582860161255c565b92505060206125d78582860161258f565b9150509250929050565b5f8115159050919050565b6125f5816125e1565b82525050565b5f60208201905061260e5f8301846125ec565b92915050565b61261d81612570565b82525050565b5f6020820190506126365f830184612614565b92915050565b5f805f606084860312156126535761265261250e565b5b5f6126608682870161255c565b93505060206126718682870161255c565b92505060406126828682870161258f565b9150509250925092565b5f60ff82169050919050565b6126a18161268c565b82525050565b5f6020820190506126ba5f830184612698565b92915050565b5f819050919050565b6126d2816126c0565b82525050565b5f6020820190506126eb5f8301846126c9565b92915050565b5f602082840312156127065761270561250e565b5b5f6127138482850161258f565b91505092915050565b5f602082840312156127315761273061250e565b5b5f61273e8482850161255c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61277981612535565b82525050565b5f61278a8383612770565b60208301905092915050565b5f602082019050919050565b5f6127ac82612747565b6127b68185612751565b93506127c183612761565b805f5b838110156127f15781516127d8888261277f565b97506127e383612796565b9250506001810190506127c4565b5085935050505092915050565b5f6020820190508181035f83015261281681846127a2565b905092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6128528161281e565b82525050565b61286181612535565b82525050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61289981612570565b82525050565b5f6128aa8383612890565b60208301905092915050565b5f602082019050919050565b5f6128cc82612867565b6128d68185612871565b93506128e183612881565b805f5b838110156129115781516128f8888261289f565b9750612903836128b6565b9250506001810190506128e4565b5085935050505092915050565b5f60e0820190506129315f83018a612849565b818103602083015261294381896124b6565b9050818103604083015261295781886124b6565b90506129666060830187612614565b6129736080830186612858565b61298060a08301856126c9565b81810360c083015261299281846128c2565b905098975050505050505050565b5f6020820190506129b35f830184612858565b92915050565b6129c28161268c565b81146129cc575f80fd5b50565b5f813590506129dd816129b9565b92915050565b6129ec816126c0565b81146129f6575f80fd5b50565b5f81359050612a07816129e3565b92915050565b5f805f805f805f60e0888a031215612a2857612a2761250e565b5b5f612a358a828b0161255c565b9750506020612a468a828b0161255c565b9650506040612a578a828b0161258f565b9550506060612a688a828b0161258f565b9450506080612a798a828b016129cf565b93505060a0612a8a8a828b016129f9565b92505060c0612a9b8a828b016129f9565b91505092959891949750929550565b5f8060408385031215612ac057612abf61250e565b5b5f612acd8582860161255c565b9250506020612ade8582860161255c565b9150509250929050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112612b0957612b08612ae8565b5b8235905067ffffffffffffffff811115612b2657612b25612aec565b5b602083019150836020820283011115612b4257612b41612af0565b5b9250929050565b612b52816125e1565b8114612b5c575f80fd5b50565b5f81359050612b6d81612b49565b92915050565b5f805f60408486031215612b8a57612b8961250e565b5b5f84013567ffffffffffffffff811115612ba757612ba6612512565b5b612bb386828701612af4565b93509350506020612bc686828701612b5f565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612c1457607f821691505b602082108103612c2757612c26612bd0565b5b50919050565b7f4164647265737320697320626c61636b6c6973746564000000000000000000005f82015250565b5f612c6160168361246e565b9150612c6c82612c2d565b602082019050919050565b5f6020820190508181035f830152612c8e81612c55565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60c082019050612cd55f8301896126c9565b612ce26020830188612858565b612cef6040830187612858565b612cfc6060830186612614565b612d096080830185612614565b612d1660a0830184612614565b979650505050505050565b5f604082019050612d345f830185612858565b612d416020830184612858565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612dac82612570565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dde57612ddd612d75565b5b600182019050919050565b5f606082019050612dfc5f830186612858565b612e096020830185612614565b612e166040830184612614565b949350505050565b5f60a082019050612e315f8301886126c9565b612e3e60208301876126c9565b612e4b60408301866126c9565b612e586060830185612614565b612e656080830184612858565b9695505050505050565b5f612e7982612570565b9150612e8483612570565b9250828203905081811115612e9c57612e9b612d75565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f608082019050612ee25f8301876126c9565b612eef6020830186612698565b612efc60408301856126c9565b612f0960608301846126c9565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f612f4982612570565b9150612f5483612570565b9250828201905080821115612f6c57612f6b612d75565b5b9291505056fea2646970667358221220ea12a93fa15d16723bb64661eba6e37fe3ee9da3b3d2a137ab2431fdcad7907a64736f6c63430008140033000000000000000000000000c2a47c9bd6b75832c6ec74be4338158b43ebad13

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106101f9575f3560e01c80637ecebe0011610118578063c2e3273d116100ab578063dd62ed3e1161007a578063dd62ed3e1461057d578063f2fde38b146105ad578063f81094f3146105c9578063fb2f3492146105e5578063fe575a8714610601576101f9565b8063c2e3273d1461050d578063c630948d14610529578063c64d0ebc14610545578063d505accf14610561576101f9565b80638da5cb5b116100e75780638da5cb5b1461047157806395d89b411461048f578063a9059cbb146104ad578063aa271e1a146104dd576101f9565b80637ecebe00146103f55780638456cb591461042557806384b0196e1461042f57806386fe8b4314610453576101f9565b806342966c68116101905780636b32810b1161015f5780636b32810b1461038157806370a082311461039f578063715018a6146103cf57806379cc6790146103d9576101f9565b806342966c68146102fb5780634334614a146103175780634f5632f8146103475780635c975abb14610363576101f9565b8063313ce567116101cc578063313ce567146102995780633644e515146102b75780633f4ba83a146102d557806340c10f19146102df576101f9565b806306fdde03146101fd578063095ea7b31461021b57806318160ddd1461024b57806323b872dd14610269575b5f80fd5b610205610631565b60405161021291906124ee565b60405180910390f35b610235600480360381019061023091906125a3565b6106c1565b60405161024291906125fb565b60405180910390f35b6102536106e3565b6040516102609190612623565b60405180910390f35b610283600480360381019061027e919061263c565b6106ec565b60405161029091906125fb565b60405180910390f35b6102a16107e5565b6040516102ae91906126a7565b60405180910390f35b6102bf6107ed565b6040516102cc91906126d8565b60405180910390f35b6102dd6107fb565b005b6102f960048036038101906102f491906125a3565b61080d565b005b610315600480360381019061031091906126f1565b610865565b005b610331600480360381019061032c919061271c565b6108bb565b60405161033e91906125fb565b60405180910390f35b610361600480360381019061035c919061271c565b6108d7565b005b61036b61093f565b60405161037891906125fb565b60405180910390f35b610389610954565b60405161039691906127fe565b60405180910390f35b6103b960048036038101906103b4919061271c565b610965565b6040516103c69190612623565b60405180910390f35b6103d76109aa565b005b6103f360048036038101906103ee91906125a3565b6109bd565b005b61040f600480360381019061040a919061271c565b610a15565b60405161041c9190612623565b60405180910390f35b61042d610a26565b005b610437610a38565b60405161044a979695949392919061291e565b60405180910390f35b61045b610add565b60405161046891906127fe565b60405180910390f35b610479610aee565b60405161048691906129a0565b60405180910390f35b610497610b16565b6040516104a491906124ee565b60405180910390f35b6104c760048036038101906104c291906125a3565b610ba6565b6040516104d491906125fb565b60405180910390f35b6104f760048036038101906104f2919061271c565b610ca4565b60405161050491906125fb565b60405180910390f35b6105276004803603810190610522919061271c565b610cc0565b005b610543600480360381019061053e919061271c565b610d28565b005b61055f600480360381019061055a919061271c565b610d45565b005b61057b60048036038101906105769190612a0d565b610dad565b005b61059760048036038101906105929190612aaa565b610ef2565b6040516105a49190612623565b60405180910390f35b6105c760048036038101906105c2919061271c565b610f74565b005b6105e360048036038101906105de919061271c565b610ff8565b005b6105ff60048036038101906105fa9190612b73565b611060565b005b61061b6004803603810190610616919061271c565b61113e565b60405161062891906125fb565b60405180910390f35b60606003805461064090612bfd565b80601f016020809104026020016040519081016040528092919081815260200182805461066c90612bfd565b80156106b75780601f1061068e576101008083540402835291602001916106b7565b820191905f5260205f20905b81548152906001019060200180831161069a57829003601f168201915b5050505050905090565b5f806106cb611190565b90506106d8818585611197565b600191505092915050565b5f600254905090565b5f8383600e5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1615801561078d5750600e5f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16155b6107cc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107c390612c77565b60405180910390fd5b6107d78686866111a9565b506001925050509392505050565b5f6012905090565b5f6107f66111d7565b905090565b61080361128d565b61080b611314565b565b61081633610ca4565b61085757336040517fe2c8c9d500000000000000000000000000000000000000000000000000000000815260040161084e91906129a0565b60405180910390fd5b6108618282611375565b5050565b61086e336108bb565b6108af57336040517fc820b10b0000000000000000000000000000000000000000000000000000000081526004016108a691906129a0565b60405180910390fd5b6108b8816113f4565b50565b5f6108d082600c61140890919063ffffffff16565b9050919050565b6108df61128d565b6108f381600c61143590919063ffffffff16565b1561093c578073ffffffffffffffffffffffffffffffffffffffff167f0a675452746933cefe3d74182e78db7afe57ba60eaa4234b5d85e9aa41b0610c60405160405180910390a25b50565b5f60055f9054906101000a900460ff16905090565b6060610960600a611462565b905090565b5f805f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6109b261128d565b6109bb5f611481565b565b6109c6336108bb565b610a0757336040517fc820b10b0000000000000000000000000000000000000000000000000000000081526004016109fe91906129a0565b60405180910390fd5b610a118282611544565b5050565b5f610a1f82611564565b9050919050565b610a2e61128d565b610a366115aa565b565b5f6060805f805f6060610a4961160c565b610a51611647565b46305f801b5f67ffffffffffffffff811115610a7057610a6f612c95565b5b604051908082528060200260200182016040528015610a9e5781602001602082028036833780820191505090505b507f0f00000000000000000000000000000000000000000000000000000000000000959493929190965096509650965096509650965090919293949596565b6060610ae9600c611462565b905090565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060048054610b2590612bfd565b80601f0160208091040260200160405190810160405280929190818152602001828054610b5190612bfd565b8015610b9c5780601f10610b7357610100808354040283529160200191610b9c565b820191905f5260205f20905b815481529060010190602001808311610b7f57829003601f168201915b5050505050905090565b5f610baf611190565b83600e5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16158015610c4e5750600e5f8273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16155b610c8d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8490612c77565b60405180910390fd5b610c978585611682565b5060019250505092915050565b5f610cb982600a61140890919063ffffffff16565b9050919050565b610cc861128d565b610cdc81600a6116a490919063ffffffff16565b15610d25578073ffffffffffffffffffffffffffffffffffffffff167fe46fef8bbff1389d9010703cf8ebb363fb3daf5bf56edc27080b67bc8d9251ea60405160405180910390a25b50565b610d3061128d565b610d3981610cc0565b610d4281610d45565b50565b610d4d61128d565b610d6181600c6116a490919063ffffffff16565b15610daa578073ffffffffffffffffffffffffffffffffffffffff167f92308bb7573b2a3d17ddb868b39d8ebec433f3194421abc22d084f89658c9bad60405160405180910390a25b50565b83421115610df257836040517f62791302000000000000000000000000000000000000000000000000000000008152600401610de99190612623565b60405180910390fd5b5f7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9888888610e208c6116d1565b89604051602001610e3696959493929190612cc2565b6040516020818303038152906040528051906020012090505f610e5882611724565b90505f610e678287878761173d565b90508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610edb57808a6040517f4b800e46000000000000000000000000000000000000000000000000000000008152600401610ed2929190612d21565b60405180910390fd5b610ee68a8a8a611197565b50505050505050505050565b5f60015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2054905092915050565b610f7c61128d565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610fec575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610fe391906129a0565b60405180910390fd5b610ff581611481565b50565b61100061128d565b61101481600a61143590919063ffffffff16565b1561105d578073ffffffffffffffffffffffffffffffffffffffff167fed998b960f6340d045f620c119730f7aa7995e7425c2401d3a5b64ff998a59e960405160405180910390a25b50565b61106861128d565b5f5b838390508110156111015781600e5f86868581811061108c5761108b612d48565b5b90506020020160208101906110a1919061271c565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff021916908315150217905550806110fa90612da2565b905061106a565b507f7dc357bd865f9219c544a8b0b14cb1583b26e3ffe765b3396ef2051d81a8de568160405161113191906125fb565b60405180910390a1505050565b5f600e5f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff169050919050565b5f33905090565b6111a4838383600161176b565b505050565b5f806111b3611190565b90506111c085828561193a565b6111cb8585856119cc565b60019150509392505050565b5f7f00000000000000000000000034bcf2b65a2758873a8c9eec180269fefa9a1d8b73ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614801561125257507f000000000000000000000000000000000000000000000000000000000000000146145b1561127f577fad48eb4e3884441c5c60d19de246492a303166b40f1f0bccca158c61ee2acff4905061128a565b611287611abc565b90505b90565b611295611190565b73ffffffffffffffffffffffffffffffffffffffff166112b3610aee565b73ffffffffffffffffffffffffffffffffffffffff1614611312576112d6611190565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161130991906129a0565b60405180910390fd5b565b61131c611b51565b5f60055f6101000a81548160ff0219169083151502179055507f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa61135e611190565b60405161136b91906129a0565b60405180910390a1565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036113e5575f6040517fec442f050000000000000000000000000000000000000000000000000000000081526004016113dc91906129a0565b60405180910390fd5b6113f05f8383611b91565b5050565b6114056113ff611190565b82611ba1565b50565b5f61142d835f018373ffffffffffffffffffffffffffffffffffffffff165f1b611c20565b905092915050565b5f61145a835f018373ffffffffffffffffffffffffffffffffffffffff165f1b611c40565b905092915050565b60605f611470835f01611d3c565b905060608190508092505050919050565b5f60095f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160095f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b61155682611550611190565b8361193a565b6115608282611ba1565b5050565b5f60085f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050919050565b6115b2611d95565b600160055f6101000a81548160ff0219169083151502179055507f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115f5611190565b60405161160291906129a0565b60405180910390a1565b606061164260067f5374616b6564204472696674000000000000000000000000000000000000000c611dd690919063ffffffff16565b905090565b606061167d60077f3100000000000000000000000000000000000000000000000000000000000001611dd690919063ffffffff16565b905090565b5f8061168c611190565b90506116998185856119cc565b600191505092915050565b5f6116c9835f018373ffffffffffffffffffffffffffffffffffffffff165f1b611e83565b905092915050565b5f60085f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f815480929190600101919050559050919050565b5f6117366117306111d7565b83611eea565b9050919050565b5f805f8061174d88888888611f2a565b92509250925061175d8282612011565b829350505050949350505050565b5f73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036117db575f6040517fe602df050000000000000000000000000000000000000000000000000000000081526004016117d291906129a0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361184b575f6040517f94280d6200000000000000000000000000000000000000000000000000000000815260040161184291906129a0565b60405180910390fd5b8160015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508015611934578273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161192b9190612623565b60405180910390a35b50505050565b5f6119458484610ef2565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146119c657818110156119b7578281836040517ffb8f41b20000000000000000000000000000000000000000000000000000000081526004016119ae93929190612de9565b60405180910390fd5b6119c584848484035f61176b565b5b50505050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611a3c575f6040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600401611a3391906129a0565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611aac575f6040517fec442f05000000000000000000000000000000000000000000000000000000008152600401611aa391906129a0565b60405180910390fd5b611ab7838383611b91565b505050565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f73099e2538d9a2d1b138caac0b1aa7bdb608d88c3c45d3106a4043617c74d9f47fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001611b36959493929190612e1e565b60405160208183030381529060405280519060200120905090565b611b5961093f565b611b8f576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b611b9c838383612173565b505050565b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611c11575f6040517f96c6fd1e000000000000000000000000000000000000000000000000000000008152600401611c0891906129a0565b60405180910390fd5b611c1c825f83611b91565b5050565b5f80836001015f8481526020019081526020015f20541415905092915050565b5f80836001015f8481526020019081526020015f205490505f8114611d31575f600182611c6d9190612e6f565b90505f6001865f0180549050611c839190612e6f565b9050808214611ce9575f865f018281548110611ca257611ca1612d48565b5b905f5260205f200154905080875f018481548110611cc357611cc2612d48565b5b905f5260205f20018190555083876001015f8381526020019081526020015f2081905550505b855f01805480611cfc57611cfb612ea2565b5b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050611d36565b5f9150505b92915050565b6060815f01805480602002602001604051908101604052809291908181526020018280548015611d8957602002820191905f5260205f20905b815481526020019060010190808311611d75575b50505050509050919050565b611d9d61093f565b15611dd4576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b606060ff5f1b8314611df257611deb8361218b565b9050611e7d565b818054611dfe90612bfd565b80601f0160208091040260200160405190810160405280929190818152602001828054611e2a90612bfd565b8015611e755780601f10611e4c57610100808354040283529160200191611e75565b820191905f5260205f20905b815481529060010190602001808311611e5857829003601f168201915b505050505090505b92915050565b5f611e8e8383611c20565b611ee057825f0182908060018154018082558091505060019003905f5260205f20015f9091909190915055825f0180549050836001015f8481526020019081526020015f208190555060019050611ee4565b5f90505b92915050565b5f6040517f190100000000000000000000000000000000000000000000000000000000000081528360028201528260228201526042812091505092915050565b5f805f7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0845f1c1115611f66575f600385925092509250612007565b5f6001888888886040515f8152602001604052604051611f899493929190612ecf565b6020604051602081039080840390855afa158015611fa9573d5f803e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611ffa575f60015f801b93509350935050612007565b805f805f1b935093509350505b9450945094915050565b5f600381111561202457612023612f12565b5b82600381111561203757612036612f12565b5b031561216f576001600381111561205157612050612f12565b5b82600381111561206457612063612f12565b5b0361209b576040517ff645eedf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260038111156120af576120ae612f12565b5b8260038111156120c2576120c1612f12565b5b0361210657805f1c6040517ffce698f70000000000000000000000000000000000000000000000000000000081526004016120fd9190612623565b60405180910390fd5b60038081111561211957612118612f12565b5b82600381111561212c5761212b612f12565b5b0361216e57806040517fd78bce0c00000000000000000000000000000000000000000000000000000000815260040161216591906126d8565b60405180910390fd5b5b5050565b61217b611d95565b6121868383836121fd565b505050565b60605f61219783612416565b90505f602067ffffffffffffffff8111156121b5576121b4612c95565b5b6040519080825280601f01601f1916602001820160405280156121e75781602001600182028036833780820191505090505b5090508181528360208201528092505050919050565b5f73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff160361224d578060025f8282546122419190612f3f565b9250508190555061231b565b5f805f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20549050818110156122d6578381836040517fe450d38c0000000000000000000000000000000000000000000000000000000081526004016122cd93929190612de9565b60405180910390fd5b8181035f808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f2081905550505b5f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612362578060025f82825403925050819055506123ac565b805f808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825401925050819055505b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516124099190612623565b60405180910390a3505050565b5f8060ff835f1c169050601f81111561245b576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80915050919050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561249b578082015181840152602081019050612480565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6124c082612464565b6124ca818561246e565b93506124da81856020860161247e565b6124e3816124a6565b840191505092915050565b5f6020820190508181035f83015261250681846124b6565b905092915050565b5f80fd5b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61253f82612516565b9050919050565b61254f81612535565b8114612559575f80fd5b50565b5f8135905061256a81612546565b92915050565b5f819050919050565b61258281612570565b811461258c575f80fd5b50565b5f8135905061259d81612579565b92915050565b5f80604083850312156125b9576125b861250e565b5b5f6125c68582860161255c565b92505060206125d78582860161258f565b9150509250929050565b5f8115159050919050565b6125f5816125e1565b82525050565b5f60208201905061260e5f8301846125ec565b92915050565b61261d81612570565b82525050565b5f6020820190506126365f830184612614565b92915050565b5f805f606084860312156126535761265261250e565b5b5f6126608682870161255c565b93505060206126718682870161255c565b92505060406126828682870161258f565b9150509250925092565b5f60ff82169050919050565b6126a18161268c565b82525050565b5f6020820190506126ba5f830184612698565b92915050565b5f819050919050565b6126d2816126c0565b82525050565b5f6020820190506126eb5f8301846126c9565b92915050565b5f602082840312156127065761270561250e565b5b5f6127138482850161258f565b91505092915050565b5f602082840312156127315761273061250e565b5b5f61273e8482850161255c565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61277981612535565b82525050565b5f61278a8383612770565b60208301905092915050565b5f602082019050919050565b5f6127ac82612747565b6127b68185612751565b93506127c183612761565b805f5b838110156127f15781516127d8888261277f565b97506127e383612796565b9250506001810190506127c4565b5085935050505092915050565b5f6020820190508181035f83015261281681846127a2565b905092915050565b5f7fff0000000000000000000000000000000000000000000000000000000000000082169050919050565b6128528161281e565b82525050565b61286181612535565b82525050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b61289981612570565b82525050565b5f6128aa8383612890565b60208301905092915050565b5f602082019050919050565b5f6128cc82612867565b6128d68185612871565b93506128e183612881565b805f5b838110156129115781516128f8888261289f565b9750612903836128b6565b9250506001810190506128e4565b5085935050505092915050565b5f60e0820190506129315f83018a612849565b818103602083015261294381896124b6565b9050818103604083015261295781886124b6565b90506129666060830187612614565b6129736080830186612858565b61298060a08301856126c9565b81810360c083015261299281846128c2565b905098975050505050505050565b5f6020820190506129b35f830184612858565b92915050565b6129c28161268c565b81146129cc575f80fd5b50565b5f813590506129dd816129b9565b92915050565b6129ec816126c0565b81146129f6575f80fd5b50565b5f81359050612a07816129e3565b92915050565b5f805f805f805f60e0888a031215612a2857612a2761250e565b5b5f612a358a828b0161255c565b9750506020612a468a828b0161255c565b9650506040612a578a828b0161258f565b9550506060612a688a828b0161258f565b9450506080612a798a828b016129cf565b93505060a0612a8a8a828b016129f9565b92505060c0612a9b8a828b016129f9565b91505092959891949750929550565b5f8060408385031215612ac057612abf61250e565b5b5f612acd8582860161255c565b9250506020612ade8582860161255c565b9150509250929050565b5f80fd5b5f80fd5b5f80fd5b5f8083601f840112612b0957612b08612ae8565b5b8235905067ffffffffffffffff811115612b2657612b25612aec565b5b602083019150836020820283011115612b4257612b41612af0565b5b9250929050565b612b52816125e1565b8114612b5c575f80fd5b50565b5f81359050612b6d81612b49565b92915050565b5f805f60408486031215612b8a57612b8961250e565b5b5f84013567ffffffffffffffff811115612ba757612ba6612512565b5b612bb386828701612af4565b93509350506020612bc686828701612b5f565b9150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f6002820490506001821680612c1457607f821691505b602082108103612c2757612c26612bd0565b5b50919050565b7f4164647265737320697320626c61636b6c6973746564000000000000000000005f82015250565b5f612c6160168361246e565b9150612c6c82612c2d565b602082019050919050565b5f6020820190508181035f830152612c8e81612c55565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60c082019050612cd55f8301896126c9565b612ce26020830188612858565b612cef6040830187612858565b612cfc6060830186612614565b612d096080830185612614565b612d1660a0830184612614565b979650505050505050565b5f604082019050612d345f830185612858565b612d416020830184612858565b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f612dac82612570565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dde57612ddd612d75565b5b600182019050919050565b5f606082019050612dfc5f830186612858565b612e096020830185612614565b612e166040830184612614565b949350505050565b5f60a082019050612e315f8301886126c9565b612e3e60208301876126c9565b612e4b60408301866126c9565b612e586060830185612614565b612e656080830184612858565b9695505050505050565b5f612e7982612570565b9150612e8483612570565b9250828203905081811115612e9c57612e9b612d75565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffd5b5f608082019050612ee25f8301876126c9565b612eef6020830186612698565b612efc60408301856126c9565b612f0960608301846126c9565b95945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b5f612f4982612570565b9150612f5483612570565b9250828201905080821115612f6c57612f6b612d75565b5b9291505056fea2646970667358221220ea12a93fa15d16723bb64661eba6e37fe3ee9da3b3d2a137ab2431fdcad7907a64736f6c63430008140033

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

000000000000000000000000c2a47c9bd6b75832c6ec74be4338158b43ebad13

-----Decoded View---------------
Arg [0] : _ownerAddress (address): 0xC2A47c9BD6b75832c6EC74be4338158b43ebad13

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c2a47c9bd6b75832c6ec74be4338158b43ebad13


Deployed Bytecode Sourcemap

106915:1564:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90914:91;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;93207:190;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92016:99;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;108050:237;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;91867:84;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;102767:114;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;107736:65;;;:::i;:::-;;107297:96;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;107401:92;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;82315:113;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;81139:162;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;84335:86;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;81608:105;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;92178:118;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;76739:103;;;:::i;:::-;;107501:158;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;102509:145;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;107667:61;;;:::i;:::-;;53251:580;;;:::i;:::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;81781:105;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;76064:87;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;91124:95;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;107809:233;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;82044:113;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;80118:158;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;79784:159;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;80451:158;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;101755:695;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;92746:142;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;76997:220;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;80793:162;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;79284:294;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;81420:120;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;90914:91;90959:13;90992:5;90985:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;90914:91;:::o;93207:190::-;93280:4;93297:13;93313:12;:10;:12::i;:::-;93297:28;;93336:31;93345:5;93352:7;93361:5;93336:8;:31::i;:::-;93385:4;93378:11;;;93207:190;;;;:::o;92016:99::-;92068:7;92095:12;;92088:19;;92016:99;:::o;108050:237::-;108205:4;108186;108192:2;78179:16;:23;78196:5;78179:23;;;;;;;;;;;;;;;;;;;;;;;;;78178:24;:50;;;;;78207:16;:21;78224:3;78207:21;;;;;;;;;;;;;;;;;;;;;;;;;78206:22;78178:50;78156:122;;;;;;;;;;;;:::i;:::-;;;;;;;;;108222:35:::1;108241:4;108247:2;108251:5;108222:18;:35::i;:::-;;108275:4;108268:11;;108050:237:::0;;;;;;;:::o;91867:84::-;91916:5;91941:2;91934:9;;91867:84;:::o;102767:114::-;102826:7;102853:20;:18;:20::i;:::-;102846:27;;102767:114;:::o;107736:65::-;75950:13;:11;:13::i;:::-;107783:10:::1;:8;:10::i;:::-;107736:65::o:0;107297:96::-;78344:20;78353:10;78344:8;:20::i;:::-;78339:61;;78389:10;78373:27;;;;;;;;;;;:::i;:::-;;;;;;;;78339:61;107368:17:::1;107374:2;107378:6;107368:5;:17::i;:::-;107297:96:::0;;:::o;107401:92::-;78466:20;78475:10;78466:8;:20::i;:::-;78461:61;;78511:10;78495:27;;;;;;;;;;;:::i;:::-;;;;;;;;78461:61;107468:17:::1;107479:5;107468:10;:17::i;:::-;107401:92:::0;:::o;82315:113::-;82370:4;82394:26;82413:6;82394:9;:18;;:26;;;;:::i;:::-;82387:33;;82315:113;;;:::o;81139:162::-;75950:13;:11;:13::i;:::-;81211:24:::1;81228:6;81211:9;:16;;:24;;;;:::i;:::-;81207:87;;;81275:6;81257:25;;;;;;;;;;;;81207:87;81139:162:::0;:::o;84335:86::-;84382:4;84406:7;;;;;;;;;;;84399:14;;84335:86;:::o;81608:105::-;81651:16;81687:18;:9;:16;:18::i;:::-;81680:25;;81608:105;:::o;92178:118::-;92243:7;92270:9;:18;92280:7;92270:18;;;;;;;;;;;;;;;;92263:25;;92178:118;;;:::o;76739:103::-;75950:13;:11;:13::i;:::-;76804:30:::1;76831:1;76804:18;:30::i;:::-;76739:103::o:0;107501:158::-;78466:20;78475:10;78466:8;:20::i;:::-;78461:61;;78511:10;78495:27;;;;;;;;;;;:::i;:::-;;;;;;;;78461:61;107621:30:::1;107636:7;107645:5;107621:14;:30::i;:::-;107501:158:::0;;:::o;102509:145::-;102600:7;102627:19;102640:5;102627:12;:19::i;:::-;102620:26;;102509:145;;;:::o;107667:61::-;75950:13;:11;:13::i;:::-;107712:8:::1;:6;:8::i;:::-;107667:61::o:0;53251:580::-;53354:13;53382:18;53415:21;53451:15;53481:25;53521:12;53548:27;53656:13;:11;:13::i;:::-;53684:16;:14;:16::i;:::-;53715:13;53751:4;53779:1;53771:10;;53810:1;53796:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;53603:220;;;;;;;;;;;;;;;;;;;;;53251:580;;;;;;;:::o;81781:105::-;81824:16;81860:18;:9;:16;:18::i;:::-;81853:25;;81781:105;:::o;76064:87::-;76110:7;76137:6;;;;;;;;;;;76130:13;;76064:87;:::o;91124:95::-;91171:13;91204:7;91197:14;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91124:95;:::o;107809:233::-;107965:4;107929:12;:10;:12::i;:::-;107943:2;78179:16;:23;78196:5;78179:23;;;;;;;;;;;;;;;;;;;;;;;;;78178:24;:50;;;;;78207:16;:21;78224:3;78207:21;;;;;;;;;;;;;;;;;;;;;;;;;78206:22;78178:50;78156:122;;;;;;;;;;;;:::i;:::-;;;;;;;;;107987:25:::1;108002:2;108006:5;107987:14;:25::i;:::-;;108030:4;108023:11;;107809:233:::0;;;;;;:::o;82044:113::-;82099:4;82123:26;82142:6;82123:9;:18;;:26;;;;:::i;:::-;82116:33;;82044:113;;;:::o;80118:158::-;75950:13;:11;:13::i;:::-;80189:21:::1;80203:6;80189:9;:13;;:21;;;;:::i;:::-;80185:84;;;80250:6;80232:25;;;;;;;;;;;;80185:84;80118:158:::0;:::o;79784:159::-;75950:13;:11;:13::i;:::-;79868:28:::1;79882:13;79868;:28::i;:::-;79907;79921:13;79907;:28::i;:::-;79784:159:::0;:::o;80451:158::-;75950:13;:11;:13::i;:::-;80522:21:::1;80536:6;80522:9;:13;;:21;;;;:::i;:::-;80518:84;;;80583:6;80565:25;;;;;;;;;;;;80518:84;80451:158:::0;:::o;101755:695::-;101985:8;101967:15;:26;101963:99;;;102041:8;102017:33;;;;;;;;;;;:::i;:::-;;;;;;;;101963:99;102074:18;101075:95;102133:5;102140:7;102149:5;102156:16;102166:5;102156:9;:16::i;:::-;102174:8;102105:78;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;102095:89;;;;;;102074:110;;102197:12;102212:28;102229:10;102212:16;:28::i;:::-;102197:43;;102253:14;102270:28;102284:4;102290:1;102293;102296;102270:13;:28::i;:::-;102253:45;;102323:5;102313:15;;:6;:15;;;102309:90;;102373:6;102381:5;102352:35;;;;;;;;;;;;:::i;:::-;;;;;;;;102309:90;102411:31;102420:5;102427:7;102436:5;102411:8;:31::i;:::-;101952:498;;;101755:695;;;;;;;:::o;92746:142::-;92826:7;92853:11;:18;92865:5;92853:18;;;;;;;;;;;;;;;:27;92872:7;92853:27;;;;;;;;;;;;;;;;92846:34;;92746:142;;;;:::o;76997:220::-;75950:13;:11;:13::i;:::-;77102:1:::1;77082:22;;:8;:22;;::::0;77078:93:::1;;77156:1;77128:31;;;;;;;;;;;:::i;:::-;;;;;;;;77078:93;77181:28;77200:8;77181:18;:28::i;:::-;76997:220:::0;:::o;80793:162::-;75950:13;:11;:13::i;:::-;80865:24:::1;80882:6;80865:9;:16;;:24;;;;:::i;:::-;80861:87;;;80929:6;80911:25;;;;;;;;;;;;80861:87;80793:162:::0;:::o;79284:294::-;75950:13;:11;:13::i;:::-;79427:9:::1;79422:109;79442:9;;:16;;79438:1;:20;79422:109;;;79513:6;79480:16;:30;79497:9;;79507:1;79497:12;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;79480:30;;;;;;;;;;;;;;;;:39;;;;;;;;;;;;;;;;;;79460:3;;;;:::i;:::-;;;79422:109;;;;79546:24;79563:6;79546:24;;;;;;:::i;:::-;;;;;;;;79284:294:::0;;;:::o;81420:120::-;81482:4;81506:16;:26;81523:8;81506:26;;;;;;;;;;;;;;;;;;;;;;;;;81499:33;;81420:120;;;:::o;74073:98::-;74126:7;74153:10;74146:17;;74073:98;:::o;98034:130::-;98119:37;98128:5;98135:7;98144:5;98151:4;98119:8;:37::i;:::-;98034:130;;;:::o;93975:249::-;94062:4;94079:15;94097:12;:10;:12::i;:::-;94079:30;;94120:37;94136:4;94142:7;94151:5;94120:15;:37::i;:::-;94168:26;94178:4;94184:2;94188:5;94168:9;:26::i;:::-;94212:4;94205:11;;;93975:249;;;;;:::o;51918:268::-;51971:7;52012:11;51995:28;;52003:4;51995:28;;;:63;;;;;52044:14;52027:13;:31;51995:63;51991:188;;;52082:22;52075:29;;;;51991:188;52144:23;:21;:23::i;:::-;52137:30;;51918:268;;:::o;76229:166::-;76300:12;:10;:12::i;:::-;76289:23;;:7;:5;:7::i;:::-;:23;;;76285:103;;76363:12;:10;:12::i;:::-;76336:40;;;;;;;;;;;:::i;:::-;;;;;;;;76285:103;76229:166::o;85236:120::-;84199:16;:14;:16::i;:::-;85305:5:::1;85295:7;;:15;;;;;;;;;;;;;;;;;;85326:22;85335:12;:10;:12::i;:::-;85326:22;;;;;;:::i;:::-;;;;;;;;85236:120::o:0;96729:213::-;96819:1;96800:21;;:7;:21;;;96796:93;;96874:1;96845:32;;;;;;;;;;;:::i;:::-;;;;;;;;96796:93;96899:35;96915:1;96919:7;96928:5;96899:7;:35::i;:::-;96729:213;;:::o;104734:89::-;104789:26;104795:12;:10;:12::i;:::-;104809:5;104789;:26::i;:::-;104734:89;:::o;9167:167::-;9247:4;9271:55;9281:3;:10;;9317:5;9301:23;;9293:32;;9271:9;:55::i;:::-;9264:62;;9167:167;;;;:::o;8923:158::-;8996:4;9020:53;9028:3;:10;;9064:5;9048:23;;9040:32;;9020:7;:53::i;:::-;9013:60;;8923:158;;;;:::o;10599:310::-;10662:16;10691:22;10716:19;10724:3;:10;;10716:7;:19::i;:::-;10691:44;;10746:23;10860:5;10850:15;;10895:6;10888:13;;;;10599:310;;;:::o;77377:191::-;77451:16;77470:6;;;;;;;;;;;77451:25;;77496:8;77487:6;;:17;;;;;;;;;;;;;;;;;;77551:8;77520:40;;77541:8;77520:40;;;;;;;;;;;;77440:128;77377:191;:::o;105152:161::-;105228:45;105244:7;105253:12;:10;:12::i;:::-;105267:5;105228:15;:45::i;:::-;105284:21;105290:7;105299:5;105284;:21::i;:::-;105152:161;;:::o;13966:109::-;14026:7;14053;:14;14061:5;14053:14;;;;;;;;;;;;;;;;14046:21;;13966:109;;;:::o;84977:118::-;83940:19;:17;:19::i;:::-;85047:4:::1;85037:7;;:14;;;;;;;;;;;;;;;;;;85067:20;85074:12;:10;:12::i;:::-;85067:20;;;;;;:::i;:::-;;;;;;;;84977:118::o:0;54160:128::-;54206:13;54239:41;54266:13;54239:5;:26;;:41;;;;:::i;:::-;54232:48;;54160:128;:::o;54623:137::-;54672:13;54705:47;54735:16;54705:8;:29;;:47;;;;:::i;:::-;54698:54;;54623:137;:::o;92501:182::-;92570:4;92587:13;92603:12;:10;:12::i;:::-;92587:28;;92626:27;92636:5;92643:2;92647:5;92626:9;:27::i;:::-;92671:4;92664:11;;;92501:182;;;;:::o;8595:152::-;8665:4;8689:50;8694:3;:10;;8730:5;8714:23;;8706:32;;8689:4;:50::i;:::-;8682:57;;8595:152;;;;:::o;14196:402::-;14256:7;14563;:14;14571:5;14563:14;;;;;;;;;;;;;;;;:16;;;;;;;;;;;;14556:23;;14196:402;;;:::o;53017:178::-;53094:7;53121:66;53154:20;:18;:20::i;:::-;53176:10;53121:32;:66::i;:::-;53114:73;;53017:178;;;:::o;61757:264::-;61842:7;61863:17;61882:18;61902:16;61922:25;61933:4;61939:1;61942;61945;61922:10;:25::i;:::-;61862:85;;;;;;61958:28;61970:5;61977:8;61958:11;:28::i;:::-;62004:9;61997:16;;;;;61757:264;;;;;;:::o;99015:443::-;99145:1;99128:19;;:5;:19;;;99124:91;;99200:1;99171:32;;;;;;;;;;;:::i;:::-;;;;;;;;99124:91;99248:1;99229:21;;:7;:21;;;99225:92;;99302:1;99274:31;;;;;;;;;;;:::i;:::-;;;;;;;;99225:92;99357:5;99327:11;:18;99339:5;99327:18;;;;;;;;;;;;;;;:27;99346:7;99327:27;;;;;;;;;;;;;;;:35;;;;99377:9;99373:78;;;99424:7;99408:31;;99417:5;99408:31;;;99433:5;99408:31;;;;;;:::i;:::-;;;;;;;;99373:78;99015:443;;;;:::o;99750:487::-;99850:24;99877:25;99887:5;99894:7;99877:9;:25::i;:::-;99850:52;;99937:17;99917:16;:37;99913:317;;99994:5;99975:16;:24;99971:132;;;100054:7;100063:16;100081:5;100027:60;;;;;;;;;;;;;:::i;:::-;;;;;;;;99971:132;100146:57;100155:5;100162:7;100190:5;100171:16;:24;100197:5;100146:8;:57::i;:::-;99913:317;99839:398;99750:487;;;:::o;94609:308::-;94709:1;94693:18;;:4;:18;;;94689:88;;94762:1;94735:30;;;;;;;;;;;:::i;:::-;;;;;;;;94689:88;94805:1;94791:16;;:2;:16;;;94787:88;;94860:1;94831:32;;;;;;;;;;;:::i;:::-;;;;;;;;94787:88;94885:24;94893:4;94899:2;94903:5;94885:7;:24::i;:::-;94609:308;;;:::o;52194:181::-;52249:7;50110:95;52308:11;52321:14;52337:13;52360:4;52286:80;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;52276:91;;;;;;52269:98;;52194:181;:::o;84703:130::-;84767:8;:6;:8::i;:::-;84762:64;;84799:15;;;;;;;;;;;;;;84762:64;84703:130::o;108295:181::-;108438:30;108452:4;108458:2;108462:5;108438:13;:30::i;:::-;108295:181;;;:::o;97270:211::-;97360:1;97341:21;;:7;:21;;;97337:91;;97413:1;97386:30;;;;;;;;;;;:::i;:::-;;;;;;;;97337:91;97438:35;97446:7;97463:1;97467:5;97438:7;:35::i;:::-;97270:211;;:::o;4420:131::-;4493:4;4542:1;4517:3;:14;;:21;4532:5;4517:21;;;;;;;;;;;;:26;;4510:33;;4420:131;;;;:::o;2934:1400::-;3000:4;3112:16;3131:3;:14;;:21;3146:5;3131:21;;;;;;;;;;;;3112:40;;3181:1;3169:8;:13;3165:1162;;3542:18;3574:1;3563:8;:12;;;;:::i;:::-;3542:33;;3590:17;3631:1;3610:3;:11;;:18;;;;:22;;;;:::i;:::-;3590:42;;3667:9;3653:10;:23;3649:385;;3697:17;3717:3;:11;;3729:9;3717:22;;;;;;;;:::i;:::-;;;;;;;;;;3697:42;;3867:9;3841:3;:11;;3853:10;3841:23;;;;;;;;:::i;:::-;;;;;;;;;:35;;;;4010:8;3982:3;:14;;:25;3997:9;3982:25;;;;;;;;;;;:36;;;;3678:356;3649:385;4115:3;:11;;:17;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;4221:3;:14;;:21;4236:5;4221:21;;;;;;;;;;;4214:28;;;4266:4;4259:11;;;;;;;3165:1162;4310:5;4303:12;;;2934:1400;;;;;:::o;5770:111::-;5826:16;5862:3;:11;;5855:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5770:111;;;:::o;84494:132::-;84560:8;:6;:8::i;:::-;84556:63;;;84592:15;;;;;;;;;;;;;;84556:63;84494:132::o;23306:273::-;23400:13;21252:66;23459:17;;23449:5;23430:46;23426:146;;23500:15;23509:5;23500:8;:15::i;:::-;23493:22;;;;23426:146;23555:5;23548:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23306:273;;;;;:::o;2342:416::-;2405:4;2427:21;2437:3;2442:5;2427:9;:21::i;:::-;2422:329;;2465:3;:11;;2482:5;2465:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2650:3;:11;;:18;;;;2626:3;:14;;:21;2641:5;2626:21;;;;;;;;;;;:42;;;;2690:4;2683:11;;;;2422:329;2734:5;2727:12;;2342:416;;;;;:::o;47717:410::-;47810:14;47922:4;47916:11;47953:10;47948:3;47941:23;48001:15;47994:4;47989:3;47985:14;47978:39;48054:10;48047:4;48042:3;48038:14;48031:34;48104:4;48099:3;48089:20;48079:30;;47890:230;47717:410;;;;:::o;60062:1556::-;60193:7;60202:12;60216:7;61136:66;61131:1;61123:10;;:79;61119:166;;;61235:1;61239:30;61271:1;61219:54;;;;;;;;61119:166;61382:14;61399:24;61409:4;61415:1;61418;61421;61399:24;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;61382:41;;61456:1;61438:20;;:6;:20;;;61434:115;;61491:1;61495:29;61534:1;61526:10;;61475:62;;;;;;;;;61434:115;61569:6;61577:20;61607:1;61599:10;;61561:49;;;;;;;60062:1556;;;;;;;;;:::o;62159:542::-;62255:20;62246:29;;;;;;;;:::i;:::-;;:5;:29;;;;;;;;:::i;:::-;;;62242:452;62292:7;62242:452;62353:29;62344:38;;;;;;;;:::i;:::-;;:5;:38;;;;;;;;:::i;:::-;;;62340:354;;62406:23;;;;;;;;;;;;;;62340:354;62460:35;62451:44;;;;;;;;:::i;:::-;;:5;:44;;;;;;;;:::i;:::-;;;62447:247;;62555:8;62547:17;;62519:46;;;;;;;;;;;:::i;:::-;;;;;;;;62447:247;62596:30;62587:39;;;;;;;;:::i;:::-;;:5;:39;;;;;;;;:::i;:::-;;;62583:111;;62673:8;62650:32;;;;;;;;;;;:::i;:::-;;;;;;;;62583:111;62159:542;;;:::o;103985:147::-;83940:19;:17;:19::i;:::-;104094:30:::1;104108:4;104114:2;104118:5;104094:13;:30::i;:::-;103985:147:::0;;;:::o;21961:415::-;22020:13;22046:11;22060:16;22071:4;22060:10;:16::i;:::-;22046:30;;22166:17;22197:2;22186:14;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;22166:34;;22291:3;22286;22279:16;22332:4;22325;22320:3;22316:14;22309:28;22365:3;22358:10;;;;21961:415;;;:::o;95241:1135::-;95347:1;95331:18;;:4;:18;;;95327:552;;95485:5;95469:12;;:21;;;;;;;:::i;:::-;;;;;;;;95327:552;;;95523:19;95545:9;:15;95555:4;95545:15;;;;;;;;;;;;;;;;95523:37;;95593:5;95579:11;:19;95575:117;;;95651:4;95657:11;95670:5;95626:50;;;;;;;;;;;;;:::i;:::-;;;;;;;;95575:117;95847:5;95833:11;:19;95815:9;:15;95825:4;95815:15;;;;;;;;;;;;;;;:37;;;;95508:371;95327:552;95909:1;95895:16;;:2;:16;;;95891:435;;96077:5;96061:12;;:21;;;;;;;;;;;95891:435;;;96294:5;96277:9;:13;96287:2;96277:13;;;;;;;;;;;;;;;;:22;;;;;;;;;;;95891:435;96358:2;96343:25;;96352:4;96343:25;;;96362:5;96343:25;;;;;;:::i;:::-;;;;;;;;95241:1135;;;:::o;22453:251::-;22514:7;22534:14;22587:4;22578;22551:33;;:40;22534:57;;22615:2;22606:6;:11;22602:71;;;22641:20;;;;;;;;;;;;;;22602:71;22690:6;22683:13;;;22453:251;;;:::o;7:99:1:-;59:6;93:5;87:12;77:22;;7:99;;;:::o;112:169::-;196:11;230:6;225:3;218:19;270:4;265:3;261:14;246:29;;112:169;;;;:::o;287:246::-;368:1;378:113;392:6;389:1;386:13;378:113;;;477:1;472:3;468:11;462:18;458:1;453:3;449:11;442:39;414:2;411:1;407:10;402:15;;378:113;;;525:1;516:6;511:3;507:16;500:27;349:184;287:246;;;:::o;539:102::-;580:6;631:2;627:7;622:2;615:5;611:14;607:28;597:38;;539:102;;;:::o;647:377::-;735:3;763:39;796:5;763:39;:::i;:::-;818:71;882:6;877:3;818:71;:::i;:::-;811:78;;898:65;956:6;951:3;944:4;937:5;933:16;898:65;:::i;:::-;988:29;1010:6;988:29;:::i;:::-;983:3;979:39;972:46;;739:285;647:377;;;;:::o;1030:313::-;1143:4;1181:2;1170:9;1166:18;1158:26;;1230:9;1224:4;1220:20;1216:1;1205:9;1201:17;1194:47;1258:78;1331:4;1322:6;1258:78;:::i;:::-;1250:86;;1030:313;;;;:::o;1430:117::-;1539:1;1536;1529:12;1553:117;1662:1;1659;1652:12;1676:126;1713:7;1753:42;1746:5;1742:54;1731:65;;1676:126;;;:::o;1808:96::-;1845:7;1874:24;1892:5;1874:24;:::i;:::-;1863:35;;1808:96;;;:::o;1910:122::-;1983:24;2001:5;1983:24;:::i;:::-;1976:5;1973:35;1963:63;;2022:1;2019;2012:12;1963:63;1910:122;:::o;2038:139::-;2084:5;2122:6;2109:20;2100:29;;2138:33;2165:5;2138:33;:::i;:::-;2038:139;;;;:::o;2183:77::-;2220:7;2249:5;2238:16;;2183:77;;;:::o;2266:122::-;2339:24;2357:5;2339:24;:::i;:::-;2332:5;2329:35;2319:63;;2378:1;2375;2368:12;2319:63;2266:122;:::o;2394:139::-;2440:5;2478:6;2465:20;2456:29;;2494:33;2521:5;2494:33;:::i;:::-;2394:139;;;;:::o;2539:474::-;2607:6;2615;2664:2;2652:9;2643:7;2639:23;2635:32;2632:119;;;2670:79;;:::i;:::-;2632:119;2790:1;2815:53;2860:7;2851:6;2840:9;2836:22;2815:53;:::i;:::-;2805:63;;2761:117;2917:2;2943:53;2988:7;2979:6;2968:9;2964:22;2943:53;:::i;:::-;2933:63;;2888:118;2539:474;;;;;:::o;3019:90::-;3053:7;3096:5;3089:13;3082:21;3071:32;;3019:90;;;:::o;3115:109::-;3196:21;3211:5;3196:21;:::i;:::-;3191:3;3184:34;3115:109;;:::o;3230:210::-;3317:4;3355:2;3344:9;3340:18;3332:26;;3368:65;3430:1;3419:9;3415:17;3406:6;3368:65;:::i;:::-;3230:210;;;;:::o;3446:118::-;3533:24;3551:5;3533:24;:::i;:::-;3528:3;3521:37;3446:118;;:::o;3570:222::-;3663:4;3701:2;3690:9;3686:18;3678:26;;3714:71;3782:1;3771:9;3767:17;3758:6;3714:71;:::i;:::-;3570:222;;;;:::o;3798:619::-;3875:6;3883;3891;3940:2;3928:9;3919:7;3915:23;3911:32;3908:119;;;3946:79;;:::i;:::-;3908:119;4066:1;4091:53;4136:7;4127:6;4116:9;4112:22;4091:53;:::i;:::-;4081:63;;4037:117;4193:2;4219:53;4264:7;4255:6;4244:9;4240:22;4219:53;:::i;:::-;4209:63;;4164:118;4321:2;4347:53;4392:7;4383:6;4372:9;4368:22;4347:53;:::i;:::-;4337:63;;4292:118;3798:619;;;;;:::o;4423:86::-;4458:7;4498:4;4491:5;4487:16;4476:27;;4423:86;;;:::o;4515:112::-;4598:22;4614:5;4598:22;:::i;:::-;4593:3;4586:35;4515:112;;:::o;4633:214::-;4722:4;4760:2;4749:9;4745:18;4737:26;;4773:67;4837:1;4826:9;4822:17;4813:6;4773:67;:::i;:::-;4633:214;;;;:::o;4853:77::-;4890:7;4919:5;4908:16;;4853:77;;;:::o;4936:118::-;5023:24;5041:5;5023:24;:::i;:::-;5018:3;5011:37;4936:118;;:::o;5060:222::-;5153:4;5191:2;5180:9;5176:18;5168:26;;5204:71;5272:1;5261:9;5257:17;5248:6;5204:71;:::i;:::-;5060:222;;;;:::o;5288:329::-;5347:6;5396:2;5384:9;5375:7;5371:23;5367:32;5364:119;;;5402:79;;:::i;:::-;5364:119;5522:1;5547:53;5592:7;5583:6;5572:9;5568:22;5547:53;:::i;:::-;5537:63;;5493:117;5288:329;;;;:::o;5623:::-;5682:6;5731:2;5719:9;5710:7;5706:23;5702:32;5699:119;;;5737:79;;:::i;:::-;5699:119;5857:1;5882:53;5927:7;5918:6;5907:9;5903:22;5882:53;:::i;:::-;5872:63;;5828:117;5623:329;;;;:::o;5958:114::-;6025:6;6059:5;6053:12;6043:22;;5958:114;;;:::o;6078:184::-;6177:11;6211:6;6206:3;6199:19;6251:4;6246:3;6242:14;6227:29;;6078:184;;;;:::o;6268:132::-;6335:4;6358:3;6350:11;;6388:4;6383:3;6379:14;6371:22;;6268:132;;;:::o;6406:108::-;6483:24;6501:5;6483:24;:::i;:::-;6478:3;6471:37;6406:108;;:::o;6520:179::-;6589:10;6610:46;6652:3;6644:6;6610:46;:::i;:::-;6688:4;6683:3;6679:14;6665:28;;6520:179;;;;:::o;6705:113::-;6775:4;6807;6802:3;6798:14;6790:22;;6705:113;;;:::o;6854:732::-;6973:3;7002:54;7050:5;7002:54;:::i;:::-;7072:86;7151:6;7146:3;7072:86;:::i;:::-;7065:93;;7182:56;7232:5;7182:56;:::i;:::-;7261:7;7292:1;7277:284;7302:6;7299:1;7296:13;7277:284;;;7378:6;7372:13;7405:63;7464:3;7449:13;7405:63;:::i;:::-;7398:70;;7491:60;7544:6;7491:60;:::i;:::-;7481:70;;7337:224;7324:1;7321;7317:9;7312:14;;7277:284;;;7281:14;7577:3;7570:10;;6978:608;;;6854:732;;;;:::o;7592:373::-;7735:4;7773:2;7762:9;7758:18;7750:26;;7822:9;7816:4;7812:20;7808:1;7797:9;7793:17;7786:47;7850:108;7953:4;7944:6;7850:108;:::i;:::-;7842:116;;7592:373;;;;:::o;7971:149::-;8007:7;8047:66;8040:5;8036:78;8025:89;;7971:149;;;:::o;8126:115::-;8211:23;8228:5;8211:23;:::i;:::-;8206:3;8199:36;8126:115;;:::o;8247:118::-;8334:24;8352:5;8334:24;:::i;:::-;8329:3;8322:37;8247:118;;:::o;8371:114::-;8438:6;8472:5;8466:12;8456:22;;8371:114;;;:::o;8491:184::-;8590:11;8624:6;8619:3;8612:19;8664:4;8659:3;8655:14;8640:29;;8491:184;;;;:::o;8681:132::-;8748:4;8771:3;8763:11;;8801:4;8796:3;8792:14;8784:22;;8681:132;;;:::o;8819:108::-;8896:24;8914:5;8896:24;:::i;:::-;8891:3;8884:37;8819:108;;:::o;8933:179::-;9002:10;9023:46;9065:3;9057:6;9023:46;:::i;:::-;9101:4;9096:3;9092:14;9078:28;;8933:179;;;;:::o;9118:113::-;9188:4;9220;9215:3;9211:14;9203:22;;9118:113;;;:::o;9267:732::-;9386:3;9415:54;9463:5;9415:54;:::i;:::-;9485:86;9564:6;9559:3;9485:86;:::i;:::-;9478:93;;9595:56;9645:5;9595:56;:::i;:::-;9674:7;9705:1;9690:284;9715:6;9712:1;9709:13;9690:284;;;9791:6;9785:13;9818:63;9877:3;9862:13;9818:63;:::i;:::-;9811:70;;9904:60;9957:6;9904:60;:::i;:::-;9894:70;;9750:224;9737:1;9734;9730:9;9725:14;;9690:284;;;9694:14;9990:3;9983:10;;9391:608;;;9267:732;;;;:::o;10005:1215::-;10354:4;10392:3;10381:9;10377:19;10369:27;;10406:69;10472:1;10461:9;10457:17;10448:6;10406:69;:::i;:::-;10522:9;10516:4;10512:20;10507:2;10496:9;10492:18;10485:48;10550:78;10623:4;10614:6;10550:78;:::i;:::-;10542:86;;10675:9;10669:4;10665:20;10660:2;10649:9;10645:18;10638:48;10703:78;10776:4;10767:6;10703:78;:::i;:::-;10695:86;;10791:72;10859:2;10848:9;10844:18;10835:6;10791:72;:::i;:::-;10873:73;10941:3;10930:9;10926:19;10917:6;10873:73;:::i;:::-;10956;11024:3;11013:9;11009:19;11000:6;10956:73;:::i;:::-;11077:9;11071:4;11067:20;11061:3;11050:9;11046:19;11039:49;11105:108;11208:4;11199:6;11105:108;:::i;:::-;11097:116;;10005:1215;;;;;;;;;;:::o;11226:222::-;11319:4;11357:2;11346:9;11342:18;11334:26;;11370:71;11438:1;11427:9;11423:17;11414:6;11370:71;:::i;:::-;11226:222;;;;:::o;11454:118::-;11525:22;11541:5;11525:22;:::i;:::-;11518:5;11515:33;11505:61;;11562:1;11559;11552:12;11505:61;11454:118;:::o;11578:135::-;11622:5;11660:6;11647:20;11638:29;;11676:31;11701:5;11676:31;:::i;:::-;11578:135;;;;:::o;11719:122::-;11792:24;11810:5;11792:24;:::i;:::-;11785:5;11782:35;11772:63;;11831:1;11828;11821:12;11772:63;11719:122;:::o;11847:139::-;11893:5;11931:6;11918:20;11909:29;;11947:33;11974:5;11947:33;:::i;:::-;11847:139;;;;:::o;11992:1199::-;12103:6;12111;12119;12127;12135;12143;12151;12200:3;12188:9;12179:7;12175:23;12171:33;12168:120;;;12207:79;;:::i;:::-;12168:120;12327:1;12352:53;12397:7;12388:6;12377:9;12373:22;12352:53;:::i;:::-;12342:63;;12298:117;12454:2;12480:53;12525:7;12516:6;12505:9;12501:22;12480:53;:::i;:::-;12470:63;;12425:118;12582:2;12608:53;12653:7;12644:6;12633:9;12629:22;12608:53;:::i;:::-;12598:63;;12553:118;12710:2;12736:53;12781:7;12772:6;12761:9;12757:22;12736:53;:::i;:::-;12726:63;;12681:118;12838:3;12865:51;12908:7;12899:6;12888:9;12884:22;12865:51;:::i;:::-;12855:61;;12809:117;12965:3;12992:53;13037:7;13028:6;13017:9;13013:22;12992:53;:::i;:::-;12982:63;;12936:119;13094:3;13121:53;13166:7;13157:6;13146:9;13142:22;13121:53;:::i;:::-;13111:63;;13065:119;11992:1199;;;;;;;;;;:::o;13197:474::-;13265:6;13273;13322:2;13310:9;13301:7;13297:23;13293:32;13290:119;;;13328:79;;:::i;:::-;13290:119;13448:1;13473:53;13518:7;13509:6;13498:9;13494:22;13473:53;:::i;:::-;13463:63;;13419:117;13575:2;13601:53;13646:7;13637:6;13626:9;13622:22;13601:53;:::i;:::-;13591:63;;13546:118;13197:474;;;;;:::o;13677:117::-;13786:1;13783;13776:12;13800:117;13909:1;13906;13899:12;13923:117;14032:1;14029;14022:12;14063:568;14136:8;14146:6;14196:3;14189:4;14181:6;14177:17;14173:27;14163:122;;14204:79;;:::i;:::-;14163:122;14317:6;14304:20;14294:30;;14347:18;14339:6;14336:30;14333:117;;;14369:79;;:::i;:::-;14333:117;14483:4;14475:6;14471:17;14459:29;;14537:3;14529:4;14521:6;14517:17;14507:8;14503:32;14500:41;14497:128;;;14544:79;;:::i;:::-;14497:128;14063:568;;;;;:::o;14637:116::-;14707:21;14722:5;14707:21;:::i;:::-;14700:5;14697:32;14687:60;;14743:1;14740;14733:12;14687:60;14637:116;:::o;14759:133::-;14802:5;14840:6;14827:20;14818:29;;14856:30;14880:5;14856:30;:::i;:::-;14759:133;;;;:::o;14898:698::-;14990:6;14998;15006;15055:2;15043:9;15034:7;15030:23;15026:32;15023:119;;;15061:79;;:::i;:::-;15023:119;15209:1;15198:9;15194:17;15181:31;15239:18;15231:6;15228:30;15225:117;;;15261:79;;:::i;:::-;15225:117;15374:80;15446:7;15437:6;15426:9;15422:22;15374:80;:::i;:::-;15356:98;;;;15152:312;15503:2;15529:50;15571:7;15562:6;15551:9;15547:22;15529:50;:::i;:::-;15519:60;;15474:115;14898:698;;;;;:::o;15602:180::-;15650:77;15647:1;15640:88;15747:4;15744:1;15737:15;15771:4;15768:1;15761:15;15788:320;15832:6;15869:1;15863:4;15859:12;15849:22;;15916:1;15910:4;15906:12;15937:18;15927:81;;15993:4;15985:6;15981:17;15971:27;;15927:81;16055:2;16047:6;16044:14;16024:18;16021:38;16018:84;;16074:18;;:::i;:::-;16018:84;15839:269;15788:320;;;:::o;16114:172::-;16254:24;16250:1;16242:6;16238:14;16231:48;16114:172;:::o;16292:366::-;16434:3;16455:67;16519:2;16514:3;16455:67;:::i;:::-;16448:74;;16531:93;16620:3;16531:93;:::i;:::-;16649:2;16644:3;16640:12;16633:19;;16292:366;;;:::o;16664:419::-;16830:4;16868:2;16857:9;16853:18;16845:26;;16917:9;16911:4;16907:20;16903:1;16892:9;16888:17;16881:47;16945:131;17071:4;16945:131;:::i;:::-;16937:139;;16664:419;;;:::o;17089:180::-;17137:77;17134:1;17127:88;17234:4;17231:1;17224:15;17258:4;17255:1;17248:15;17275:775;17508:4;17546:3;17535:9;17531:19;17523:27;;17560:71;17628:1;17617:9;17613:17;17604:6;17560:71;:::i;:::-;17641:72;17709:2;17698:9;17694:18;17685:6;17641:72;:::i;:::-;17723;17791:2;17780:9;17776:18;17767:6;17723:72;:::i;:::-;17805;17873:2;17862:9;17858:18;17849:6;17805:72;:::i;:::-;17887:73;17955:3;17944:9;17940:19;17931:6;17887:73;:::i;:::-;17970;18038:3;18027:9;18023:19;18014:6;17970:73;:::i;:::-;17275:775;;;;;;;;;:::o;18056:332::-;18177:4;18215:2;18204:9;18200:18;18192:26;;18228:71;18296:1;18285:9;18281:17;18272:6;18228:71;:::i;:::-;18309:72;18377:2;18366:9;18362:18;18353:6;18309:72;:::i;:::-;18056:332;;;;;:::o;18394:180::-;18442:77;18439:1;18432:88;18539:4;18536:1;18529:15;18563:4;18560:1;18553:15;18580:180;18628:77;18625:1;18618:88;18725:4;18722:1;18715:15;18749:4;18746:1;18739:15;18766:233;18805:3;18828:24;18846:5;18828:24;:::i;:::-;18819:33;;18874:66;18867:5;18864:77;18861:103;;18944:18;;:::i;:::-;18861:103;18991:1;18984:5;18980:13;18973:20;;18766:233;;;:::o;19005:442::-;19154:4;19192:2;19181:9;19177:18;19169:26;;19205:71;19273:1;19262:9;19258:17;19249:6;19205:71;:::i;:::-;19286:72;19354:2;19343:9;19339:18;19330:6;19286:72;:::i;:::-;19368;19436:2;19425:9;19421:18;19412:6;19368:72;:::i;:::-;19005:442;;;;;;:::o;19453:664::-;19658:4;19696:3;19685:9;19681:19;19673:27;;19710:71;19778:1;19767:9;19763:17;19754:6;19710:71;:::i;:::-;19791:72;19859:2;19848:9;19844:18;19835:6;19791:72;:::i;:::-;19873;19941:2;19930:9;19926:18;19917:6;19873:72;:::i;:::-;19955;20023:2;20012:9;20008:18;19999:6;19955:72;:::i;:::-;20037:73;20105:3;20094:9;20090:19;20081:6;20037:73;:::i;:::-;19453:664;;;;;;;;:::o;20123:194::-;20163:4;20183:20;20201:1;20183:20;:::i;:::-;20178:25;;20217:20;20235:1;20217:20;:::i;:::-;20212:25;;20261:1;20258;20254:9;20246:17;;20285:1;20279:4;20276:11;20273:37;;;20290:18;;:::i;:::-;20273:37;20123:194;;;;:::o;20323:180::-;20371:77;20368:1;20361:88;20468:4;20465:1;20458:15;20492:4;20489:1;20482:15;20509:545;20682:4;20720:3;20709:9;20705:19;20697:27;;20734:71;20802:1;20791:9;20787:17;20778:6;20734:71;:::i;:::-;20815:68;20879:2;20868:9;20864:18;20855:6;20815:68;:::i;:::-;20893:72;20961:2;20950:9;20946:18;20937:6;20893:72;:::i;:::-;20975;21043:2;21032:9;21028:18;21019:6;20975:72;:::i;:::-;20509:545;;;;;;;:::o;21060:180::-;21108:77;21105:1;21098:88;21205:4;21202:1;21195:15;21229:4;21226:1;21219:15;21246:191;21286:3;21305:20;21323:1;21305:20;:::i;:::-;21300:25;;21339:20;21357:1;21339:20;:::i;:::-;21334:25;;21382:1;21379;21375:9;21368:16;;21403:3;21400:1;21397:10;21394:36;;;21410:18;;:::i;:::-;21394:36;21246:191;;;;:::o

Swarm Source

ipfs://ea12a93fa15d16723bb64661eba6e37fe3ee9da3b3d2a137ab2431fdcad7907a
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.