ETH Price: $2,938.77 (-0.31%)

Token

BurntHermes Boost (bHERMES-B)

Overview

Max Total Supply

281,320,421.438102500362619042 bHERMES-B

Holders

453

Transfers

-
3

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
bHermesBoost

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";

import {ERC20Boost} from "src/erc-20/ERC20Boost.sol";

import {IbHermesUnderlying} from "../interfaces/IbHermesUnderlying.sol";

/// @title Library for bHermesBoost deployment
library DeployBurntHermesBoost {
    function deploy(address _owner) external returns (bHermesBoost) {
        return new bHermesBoost(_owner);
    }
}

/**
 * @title bHermesBoost: Earns rights to boosted Hermes yield
 *  @author Maia DAO (https://github.com/Maia-DAO)
 *  @notice An ERC20 with an embedded attachment mechanism to
 *          keep track of boost allocations to gauges.
 */
contract bHermesBoost is ERC20Boost, IbHermesUnderlying {
    /// @inheritdoc IbHermesUnderlying
    address public immutable override bHermes;

    constructor(address _owner) ERC20("BurntHermes Boost", "bHERMES-B", 18) {
        _initializeOwner(_owner);
        bHermes = msg.sender;
    }

    /// @inheritdoc IbHermesUnderlying
    function mint(address to, uint256 amount) external override onlybHermes {
        _mint(to, amount);
    }

    modifier onlybHermes() {
        if (msg.sender != bHermes) revert NotbHermes();
        _;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @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 of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @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._indexes[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 read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 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 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

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

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

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

            // Delete the index for the deleted slot
            delete set._indexes[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._indexes[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;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 4 of 8 : SafeCastLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe integer casting library that reverts on overflow.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
/// @dev Optimized for runtime gas for very high number of optimizer runs (i.e. >= 1000000).
library SafeCastLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    error Overflow();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*          UNSIGNED INTEGER SAFE CASTING OPERATIONS          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function toUint8(uint256 x) internal pure returns (uint8) {
        if (x >= 1 << 8) _revertOverflow();
        return uint8(x);
    }

    function toUint16(uint256 x) internal pure returns (uint16) {
        if (x >= 1 << 16) _revertOverflow();
        return uint16(x);
    }

    function toUint24(uint256 x) internal pure returns (uint24) {
        if (x >= 1 << 24) _revertOverflow();
        return uint24(x);
    }

    function toUint32(uint256 x) internal pure returns (uint32) {
        if (x >= 1 << 32) _revertOverflow();
        return uint32(x);
    }

    function toUint40(uint256 x) internal pure returns (uint40) {
        if (x >= 1 << 40) _revertOverflow();
        return uint40(x);
    }

    function toUint48(uint256 x) internal pure returns (uint48) {
        if (x >= 1 << 48) _revertOverflow();
        return uint48(x);
    }

    function toUint56(uint256 x) internal pure returns (uint56) {
        if (x >= 1 << 56) _revertOverflow();
        return uint56(x);
    }

    function toUint64(uint256 x) internal pure returns (uint64) {
        if (x >= 1 << 64) _revertOverflow();
        return uint64(x);
    }

    function toUint72(uint256 x) internal pure returns (uint72) {
        if (x >= 1 << 72) _revertOverflow();
        return uint72(x);
    }

    function toUint80(uint256 x) internal pure returns (uint80) {
        if (x >= 1 << 80) _revertOverflow();
        return uint80(x);
    }

    function toUint88(uint256 x) internal pure returns (uint88) {
        if (x >= 1 << 88) _revertOverflow();
        return uint88(x);
    }

    function toUint96(uint256 x) internal pure returns (uint96) {
        if (x >= 1 << 96) _revertOverflow();
        return uint96(x);
    }

    function toUint104(uint256 x) internal pure returns (uint104) {
        if (x >= 1 << 104) _revertOverflow();
        return uint104(x);
    }

    function toUint112(uint256 x) internal pure returns (uint112) {
        if (x >= 1 << 112) _revertOverflow();
        return uint112(x);
    }

    function toUint120(uint256 x) internal pure returns (uint120) {
        if (x >= 1 << 120) _revertOverflow();
        return uint120(x);
    }

    function toUint128(uint256 x) internal pure returns (uint128) {
        if (x >= 1 << 128) _revertOverflow();
        return uint128(x);
    }

    function toUint136(uint256 x) internal pure returns (uint136) {
        if (x >= 1 << 136) _revertOverflow();
        return uint136(x);
    }

    function toUint144(uint256 x) internal pure returns (uint144) {
        if (x >= 1 << 144) _revertOverflow();
        return uint144(x);
    }

    function toUint152(uint256 x) internal pure returns (uint152) {
        if (x >= 1 << 152) _revertOverflow();
        return uint152(x);
    }

    function toUint160(uint256 x) internal pure returns (uint160) {
        if (x >= 1 << 160) _revertOverflow();
        return uint160(x);
    }

    function toUint168(uint256 x) internal pure returns (uint168) {
        if (x >= 1 << 168) _revertOverflow();
        return uint168(x);
    }

    function toUint176(uint256 x) internal pure returns (uint176) {
        if (x >= 1 << 176) _revertOverflow();
        return uint176(x);
    }

    function toUint184(uint256 x) internal pure returns (uint184) {
        if (x >= 1 << 184) _revertOverflow();
        return uint184(x);
    }

    function toUint192(uint256 x) internal pure returns (uint192) {
        if (x >= 1 << 192) _revertOverflow();
        return uint192(x);
    }

    function toUint200(uint256 x) internal pure returns (uint200) {
        if (x >= 1 << 200) _revertOverflow();
        return uint200(x);
    }

    function toUint208(uint256 x) internal pure returns (uint208) {
        if (x >= 1 << 208) _revertOverflow();
        return uint208(x);
    }

    function toUint216(uint256 x) internal pure returns (uint216) {
        if (x >= 1 << 216) _revertOverflow();
        return uint216(x);
    }

    function toUint224(uint256 x) internal pure returns (uint224) {
        if (x >= 1 << 224) _revertOverflow();
        return uint224(x);
    }

    function toUint232(uint256 x) internal pure returns (uint232) {
        if (x >= 1 << 232) _revertOverflow();
        return uint232(x);
    }

    function toUint240(uint256 x) internal pure returns (uint240) {
        if (x >= 1 << 240) _revertOverflow();
        return uint240(x);
    }

    function toUint248(uint256 x) internal pure returns (uint248) {
        if (x >= 1 << 248) _revertOverflow();
        return uint248(x);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*           SIGNED INTEGER SAFE CASTING OPERATIONS           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function toInt8(int256 x) internal pure returns (int8) {
        unchecked {
            if (((1 << 7) + uint256(x)) >> 8 == uint256(0)) return int8(x);
            _revertOverflow();
        }
    }

    function toInt16(int256 x) internal pure returns (int16) {
        unchecked {
            if (((1 << 15) + uint256(x)) >> 16 == uint256(0)) return int16(x);
            _revertOverflow();
        }
    }

    function toInt24(int256 x) internal pure returns (int24) {
        unchecked {
            if (((1 << 23) + uint256(x)) >> 24 == uint256(0)) return int24(x);
            _revertOverflow();
        }
    }

    function toInt32(int256 x) internal pure returns (int32) {
        unchecked {
            if (((1 << 31) + uint256(x)) >> 32 == uint256(0)) return int32(x);
            _revertOverflow();
        }
    }

    function toInt40(int256 x) internal pure returns (int40) {
        unchecked {
            if (((1 << 39) + uint256(x)) >> 40 == uint256(0)) return int40(x);
            _revertOverflow();
        }
    }

    function toInt48(int256 x) internal pure returns (int48) {
        unchecked {
            if (((1 << 47) + uint256(x)) >> 48 == uint256(0)) return int48(x);
            _revertOverflow();
        }
    }

    function toInt56(int256 x) internal pure returns (int56) {
        unchecked {
            if (((1 << 55) + uint256(x)) >> 56 == uint256(0)) return int56(x);
            _revertOverflow();
        }
    }

    function toInt64(int256 x) internal pure returns (int64) {
        unchecked {
            if (((1 << 63) + uint256(x)) >> 64 == uint256(0)) return int64(x);
            _revertOverflow();
        }
    }

    function toInt72(int256 x) internal pure returns (int72) {
        unchecked {
            if (((1 << 71) + uint256(x)) >> 72 == uint256(0)) return int72(x);
            _revertOverflow();
        }
    }

    function toInt80(int256 x) internal pure returns (int80) {
        unchecked {
            if (((1 << 79) + uint256(x)) >> 80 == uint256(0)) return int80(x);
            _revertOverflow();
        }
    }

    function toInt88(int256 x) internal pure returns (int88) {
        unchecked {
            if (((1 << 87) + uint256(x)) >> 88 == uint256(0)) return int88(x);
            _revertOverflow();
        }
    }

    function toInt96(int256 x) internal pure returns (int96) {
        unchecked {
            if (((1 << 95) + uint256(x)) >> 96 == uint256(0)) return int96(x);
            _revertOverflow();
        }
    }

    function toInt104(int256 x) internal pure returns (int104) {
        unchecked {
            if (((1 << 103) + uint256(x)) >> 104 == uint256(0)) return int104(x);
            _revertOverflow();
        }
    }

    function toInt112(int256 x) internal pure returns (int112) {
        unchecked {
            if (((1 << 111) + uint256(x)) >> 112 == uint256(0)) return int112(x);
            _revertOverflow();
        }
    }

    function toInt120(int256 x) internal pure returns (int120) {
        unchecked {
            if (((1 << 119) + uint256(x)) >> 120 == uint256(0)) return int120(x);
            _revertOverflow();
        }
    }

    function toInt128(int256 x) internal pure returns (int128) {
        unchecked {
            if (((1 << 127) + uint256(x)) >> 128 == uint256(0)) return int128(x);
            _revertOverflow();
        }
    }

    function toInt136(int256 x) internal pure returns (int136) {
        unchecked {
            if (((1 << 135) + uint256(x)) >> 136 == uint256(0)) return int136(x);
            _revertOverflow();
        }
    }

    function toInt144(int256 x) internal pure returns (int144) {
        unchecked {
            if (((1 << 143) + uint256(x)) >> 144 == uint256(0)) return int144(x);
            _revertOverflow();
        }
    }

    function toInt152(int256 x) internal pure returns (int152) {
        unchecked {
            if (((1 << 151) + uint256(x)) >> 152 == uint256(0)) return int152(x);
            _revertOverflow();
        }
    }

    function toInt160(int256 x) internal pure returns (int160) {
        unchecked {
            if (((1 << 159) + uint256(x)) >> 160 == uint256(0)) return int160(x);
            _revertOverflow();
        }
    }

    function toInt168(int256 x) internal pure returns (int168) {
        unchecked {
            if (((1 << 167) + uint256(x)) >> 168 == uint256(0)) return int168(x);
            _revertOverflow();
        }
    }

    function toInt176(int256 x) internal pure returns (int176) {
        unchecked {
            if (((1 << 175) + uint256(x)) >> 176 == uint256(0)) return int176(x);
            _revertOverflow();
        }
    }

    function toInt184(int256 x) internal pure returns (int184) {
        unchecked {
            if (((1 << 183) + uint256(x)) >> 184 == uint256(0)) return int184(x);
            _revertOverflow();
        }
    }

    function toInt192(int256 x) internal pure returns (int192) {
        unchecked {
            if (((1 << 191) + uint256(x)) >> 192 == uint256(0)) return int192(x);
            _revertOverflow();
        }
    }

    function toInt200(int256 x) internal pure returns (int200) {
        unchecked {
            if (((1 << 199) + uint256(x)) >> 200 == uint256(0)) return int200(x);
            _revertOverflow();
        }
    }

    function toInt208(int256 x) internal pure returns (int208) {
        unchecked {
            if (((1 << 207) + uint256(x)) >> 208 == uint256(0)) return int208(x);
            _revertOverflow();
        }
    }

    function toInt216(int256 x) internal pure returns (int216) {
        unchecked {
            if (((1 << 215) + uint256(x)) >> 216 == uint256(0)) return int216(x);
            _revertOverflow();
        }
    }

    function toInt224(int256 x) internal pure returns (int224) {
        unchecked {
            if (((1 << 223) + uint256(x)) >> 224 == uint256(0)) return int224(x);
            _revertOverflow();
        }
    }

    function toInt232(int256 x) internal pure returns (int232) {
        unchecked {
            if (((1 << 231) + uint256(x)) >> 232 == uint256(0)) return int232(x);
            _revertOverflow();
        }
    }

    function toInt240(int256 x) internal pure returns (int240) {
        unchecked {
            if (((1 << 239) + uint256(x)) >> 240 == uint256(0)) return int240(x);
            _revertOverflow();
        }
    }

    function toInt248(int256 x) internal pure returns (int248) {
        unchecked {
            if (((1 << 247) + uint256(x)) >> 248 == uint256(0)) return int248(x);
            _revertOverflow();
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               OTHER SAFE CASTING OPERATIONS                */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function toInt8(uint256 x) internal pure returns (int8) {
        if (x >= 1 << 7) _revertOverflow();
        return int8(int256(x));
    }

    function toInt16(uint256 x) internal pure returns (int16) {
        if (x >= 1 << 15) _revertOverflow();
        return int16(int256(x));
    }

    function toInt24(uint256 x) internal pure returns (int24) {
        if (x >= 1 << 23) _revertOverflow();
        return int24(int256(x));
    }

    function toInt32(uint256 x) internal pure returns (int32) {
        if (x >= 1 << 31) _revertOverflow();
        return int32(int256(x));
    }

    function toInt40(uint256 x) internal pure returns (int40) {
        if (x >= 1 << 39) _revertOverflow();
        return int40(int256(x));
    }

    function toInt48(uint256 x) internal pure returns (int48) {
        if (x >= 1 << 47) _revertOverflow();
        return int48(int256(x));
    }

    function toInt56(uint256 x) internal pure returns (int56) {
        if (x >= 1 << 55) _revertOverflow();
        return int56(int256(x));
    }

    function toInt64(uint256 x) internal pure returns (int64) {
        if (x >= 1 << 63) _revertOverflow();
        return int64(int256(x));
    }

    function toInt72(uint256 x) internal pure returns (int72) {
        if (x >= 1 << 71) _revertOverflow();
        return int72(int256(x));
    }

    function toInt80(uint256 x) internal pure returns (int80) {
        if (x >= 1 << 79) _revertOverflow();
        return int80(int256(x));
    }

    function toInt88(uint256 x) internal pure returns (int88) {
        if (x >= 1 << 87) _revertOverflow();
        return int88(int256(x));
    }

    function toInt96(uint256 x) internal pure returns (int96) {
        if (x >= 1 << 95) _revertOverflow();
        return int96(int256(x));
    }

    function toInt104(uint256 x) internal pure returns (int104) {
        if (x >= 1 << 103) _revertOverflow();
        return int104(int256(x));
    }

    function toInt112(uint256 x) internal pure returns (int112) {
        if (x >= 1 << 111) _revertOverflow();
        return int112(int256(x));
    }

    function toInt120(uint256 x) internal pure returns (int120) {
        if (x >= 1 << 119) _revertOverflow();
        return int120(int256(x));
    }

    function toInt128(uint256 x) internal pure returns (int128) {
        if (x >= 1 << 127) _revertOverflow();
        return int128(int256(x));
    }

    function toInt136(uint256 x) internal pure returns (int136) {
        if (x >= 1 << 135) _revertOverflow();
        return int136(int256(x));
    }

    function toInt144(uint256 x) internal pure returns (int144) {
        if (x >= 1 << 143) _revertOverflow();
        return int144(int256(x));
    }

    function toInt152(uint256 x) internal pure returns (int152) {
        if (x >= 1 << 151) _revertOverflow();
        return int152(int256(x));
    }

    function toInt160(uint256 x) internal pure returns (int160) {
        if (x >= 1 << 159) _revertOverflow();
        return int160(int256(x));
    }

    function toInt168(uint256 x) internal pure returns (int168) {
        if (x >= 1 << 167) _revertOverflow();
        return int168(int256(x));
    }

    function toInt176(uint256 x) internal pure returns (int176) {
        if (x >= 1 << 175) _revertOverflow();
        return int176(int256(x));
    }

    function toInt184(uint256 x) internal pure returns (int184) {
        if (x >= 1 << 183) _revertOverflow();
        return int184(int256(x));
    }

    function toInt192(uint256 x) internal pure returns (int192) {
        if (x >= 1 << 191) _revertOverflow();
        return int192(int256(x));
    }

    function toInt200(uint256 x) internal pure returns (int200) {
        if (x >= 1 << 199) _revertOverflow();
        return int200(int256(x));
    }

    function toInt208(uint256 x) internal pure returns (int208) {
        if (x >= 1 << 207) _revertOverflow();
        return int208(int256(x));
    }

    function toInt216(uint256 x) internal pure returns (int216) {
        if (x >= 1 << 215) _revertOverflow();
        return int216(int256(x));
    }

    function toInt224(uint256 x) internal pure returns (int224) {
        if (x >= 1 << 223) _revertOverflow();
        return int224(int256(x));
    }

    function toInt232(uint256 x) internal pure returns (int232) {
        if (x >= 1 << 231) _revertOverflow();
        return int232(int256(x));
    }

    function toInt240(uint256 x) internal pure returns (int240) {
        if (x >= 1 << 239) _revertOverflow();
        return int240(int256(x));
    }

    function toInt248(uint256 x) internal pure returns (int248) {
        if (x >= 1 << 247) _revertOverflow();
        return int248(int256(x));
    }

    function toInt256(uint256 x) internal pure returns (int256) {
        if (int256(x) >= 0) return int256(x);
        _revertOverflow();
    }

    function toUint256(int256 x) internal pure returns (uint256) {
        if (x >= 0) return uint256(x);
        _revertOverflow();
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function _revertOverflow() private pure {
        /// @solidity memory-safe-assembly
        assembly {
            // Store the function selector of `Overflow()`.
            mstore(0x00, 0x35278d12)
            // Revert with (offset, size).
            revert(0x1c, 0x04)
        }
    }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import {Ownable} from "lib/solady/src/auth/Ownable.sol";
import {SafeCastLib} from "lib/solady/src/utils/SafeCastLib.sol";

import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";

import {EnumerableSet} from "lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol";

import {IERC20Boost} from "./interfaces/IERC20Boost.sol";

/// @title An ERC20 with an embedded attachment mechanism to keep track of boost
///        allocations to gauges.
abstract contract ERC20Boost is ERC20, Ownable, IERC20Boost {
    using EnumerableSet for EnumerableSet.AddressSet;
    using SafeCastLib for *;

    /*///////////////////////////////////////////////////////////////
                            GAUGE STATE
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC20Boost
    mapping(address user => mapping(address gauge => GaugeState userGaugeState)) public override getUserGaugeBoost;

    /// @inheritdoc IERC20Boost
    mapping(address user => uint256 boost) public override getUserBoost;

    mapping(address user => EnumerableSet.AddressSet userGaugeSet) internal _userGauges;

    EnumerableSet.AddressSet internal _gauges;

    // Store deprecated gauges in case a user needs to free dead boost
    EnumerableSet.AddressSet internal _deprecatedGauges;

    /*///////////////////////////////////////////////////////////////
                            VIEW HELPERS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC20Boost
    function gauges() external view override returns (address[] memory) {
        return _gauges.values();
    }

    /// @inheritdoc IERC20Boost
    function gauges(uint256 offset, uint256 num) external view override returns (address[] memory values) {
        values = new address[](num);
        for (uint256 i = 0; i < num;) {
            unchecked {
                values[i] = _gauges.at(offset + i); // will revert if out of bounds
                i++;
            }
        }
    }

    /// @inheritdoc IERC20Boost
    function isGauge(address gauge) external view override returns (bool) {
        return _gauges.contains(gauge) && !_deprecatedGauges.contains(gauge);
    }

    /// @inheritdoc IERC20Boost
    function numGauges() external view override returns (uint256) {
        return _gauges.length();
    }

    /// @inheritdoc IERC20Boost
    function deprecatedGauges() external view override returns (address[] memory) {
        return _deprecatedGauges.values();
    }

    /// @inheritdoc IERC20Boost
    function numDeprecatedGauges() external view override returns (uint256) {
        return _deprecatedGauges.length();
    }

    /// @inheritdoc IERC20Boost
    function freeGaugeBoost(address user) public view override returns (uint256) {
        return balanceOf[user] - getUserBoost[user];
    }

    /// @inheritdoc IERC20Boost
    function userGauges(address user) external view override returns (address[] memory) {
        return _userGauges[user].values();
    }

    /// @inheritdoc IERC20Boost
    function isUserGauge(address user, address gauge) external view override returns (bool) {
        return _userGauges[user].contains(gauge);
    }

    /// @inheritdoc IERC20Boost
    function userGauges(address user, uint256 offset, uint256 num)
        external
        view
        override
        returns (address[] memory values)
    {
        values = new address[](num);
        EnumerableSet.AddressSet storage userGaugesSet = _userGauges[user];
        for (uint256 i = 0; i < num;) {
            unchecked {
                values[i] = userGaugesSet.at(offset + i); // will revert if out of bounds
                i++;
            }
        }
    }

    /// @inheritdoc IERC20Boost
    function numUserGauges(address user) external view override returns (uint256) {
        return _userGauges[user].length();
    }

    /*///////////////////////////////////////////////////////////////
                        GAUGE OPERATIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC20Boost
    function attach(address user) external override {
        if (!_gauges.contains(msg.sender) || _deprecatedGauges.contains(msg.sender)) {
            revert InvalidGauge();
        }

        // idempotent add
        if (!_userGauges[user].add(msg.sender)) revert GaugeAlreadyAttached();

        uint128 userGaugeBoost = balanceOf[user].toUint128();

        if (getUserBoost[user] < userGaugeBoost) {
            getUserBoost[user] = userGaugeBoost;
            emit UpdateUserBoost(user, userGaugeBoost);
        }

        uint256 _totalSupply = totalSupply;
        if (_totalSupply > 0) {
            GaugeState storage userBoost = getUserGaugeBoost[user][msg.sender];
            userBoost.userGaugeBoost = userGaugeBoost;
            userBoost.totalGaugeBoost = _totalSupply.toUint128();
        }

        emit Attach(user, msg.sender, userGaugeBoost);
    }

    /// @inheritdoc IERC20Boost
    function detach(address user) external {
        require(_userGauges[user].remove(msg.sender)); // Remove from set. Should never fail.
        delete getUserGaugeBoost[user][msg.sender];

        emit Detach(user, msg.sender);
    }

    /*///////////////////////////////////////////////////////////////
                        USER GAUGE OPERATIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC20Boost
    function updateUserBoost(address user) external override {
        uint256 userBoost;

        address[] memory gaugeList = _userGauges[user].values();

        uint256 length = gaugeList.length;
        for (uint256 i = 0; i < length;) {
            uint256 gaugeBoost = getUserGaugeBoost[user][gaugeList[i]].userGaugeBoost;

            if (userBoost < gaugeBoost) userBoost = gaugeBoost;

            unchecked {
                i++;
            }
        }
        getUserBoost[user] = userBoost;

        emit UpdateUserBoost(user, userBoost);
    }

    /// @inheritdoc IERC20Boost
    function decrementGaugeBoost(address gauge, uint256 boost) public override {
        GaugeState storage gaugeState = getUserGaugeBoost[msg.sender][gauge];
        uint256 _userGaugeBoost = gaugeState.userGaugeBoost;

        if (_deprecatedGauges.contains(gauge) || boost >= _userGaugeBoost) {
            require(_userGauges[msg.sender].remove(gauge)); // Remove from set. Should never fail.
            delete getUserGaugeBoost[msg.sender][gauge];

            emit Detach(msg.sender, gauge);
        } else {
            _userGaugeBoost = _userGaugeBoost - boost;
            gaugeState.userGaugeBoost = _userGaugeBoost.toUint128();

            emit DecrementUserGaugeBoost(msg.sender, gauge, _userGaugeBoost);
        }
    }

    /// @inheritdoc IERC20Boost
    function decrementGaugeAllBoost(address gauge) external override {
        require(_userGauges[msg.sender].remove(gauge)); // Remove from set. Should never fail.
        delete getUserGaugeBoost[msg.sender][gauge];

        emit Detach(msg.sender, gauge);
    }

    /// @inheritdoc IERC20Boost
    function decrementAllGaugesBoost(uint256 boost) external override {
        decrementGaugesBoostIndexed(boost, 0, _userGauges[msg.sender].length());
    }

    /// @inheritdoc IERC20Boost
    function decrementGaugesBoostIndexed(uint256 boost, uint256 offset, uint256 num) public override {
        EnumerableSet.AddressSet storage userGaugesSet = _userGauges[msg.sender];

        address[] memory gaugeList = userGaugesSet.values();

        uint256 length = gaugeList.length;
        for (uint256 i = 0; i < num && i < length;) {
            address gauge = gaugeList[offset + i];

            GaugeState storage gaugeState = getUserGaugeBoost[msg.sender][gauge];
            uint256 _userGaugeBoost = gaugeState.userGaugeBoost;

            if (_deprecatedGauges.contains(gauge) || boost >= _userGaugeBoost) {
                require(userGaugesSet.remove(gauge)); // Remove from set. Should never fail.
                delete getUserGaugeBoost[msg.sender][gauge];

                emit Detach(msg.sender, gauge);
            } else {
                _userGaugeBoost = _userGaugeBoost - boost;
                gaugeState.userGaugeBoost = _userGaugeBoost.toUint128();

                emit DecrementUserGaugeBoost(msg.sender, gauge, _userGaugeBoost);
            }

            unchecked {
                i++;
            }
        }
    }

    /// @inheritdoc IERC20Boost
    function decrementAllGaugesAllBoost() external override {
        EnumerableSet.AddressSet storage userGaugesSet = _userGauges[msg.sender];

        // Loop through all user gauges, live and deprecated
        address[] memory gaugeList = userGaugesSet.values();

        // Free gauges until through the entire list
        uint256 size = gaugeList.length;
        for (uint256 i = 0; i < size;) {
            address gauge = gaugeList[i];

            require(userGaugesSet.remove(gauge)); // Remove from set. Should never fail.
            delete getUserGaugeBoost[msg.sender][gauge];

            emit Detach(msg.sender, gauge);

            unchecked {
                i++;
            }
        }

        delete getUserBoost[msg.sender];

        emit UpdateUserBoost(msg.sender, 0);
    }

    /*///////////////////////////////////////////////////////////////
                        ADMIN GAUGE OPERATIONS
    ///////////////////////////////////////////////////////////////*/

    /// @inheritdoc IERC20Boost
    function addGauge(address gauge) external override onlyOwner {
        _addGauge(gauge);
    }

    function _addGauge(address gauge) internal {
        // add and fail loud if zero address or already present and not deprecated
        if (gauge == address(0) || !(_gauges.add(gauge) || _deprecatedGauges.remove(gauge))) revert InvalidGauge();

        emit AddGauge(gauge);
    }

    /// @inheritdoc IERC20Boost
    function removeGauge(address gauge) external override onlyOwner {
        _removeGauge(gauge);
    }

    function _removeGauge(address gauge) internal {
        // add to deprecated and fail loud if not present
        if (!_deprecatedGauges.add(gauge)) revert InvalidGauge();

        emit RemoveGauge(gauge);
    }

    /// @inheritdoc IERC20Boost
    function replaceGauge(address oldGauge, address newGauge) external override onlyOwner {
        _removeGauge(oldGauge);
        _addGauge(newGauge);
    }

    /*///////////////////////////////////////////////////////////////
                             ERC20 LOGIC
    ///////////////////////////////////////////////////////////////*/

    /// NOTE: any "removal" of tokens from a user requires notAttached < amount.

    /**
     * @notice Burns `amount` of tokens from `from` address.
     * @dev User must have enough free boost.
     * @param from The address to burn tokens from.
     * @param amount The amount of tokens to burn.
     */
    function _burn(address from, uint256 amount) internal override notAttached(from, amount) {
        super._burn(from, amount);
    }

    /**
     * @notice Transfers `amount` of tokens from `msg.sender` to `to` address.
     * @dev User must have enough free boost.
     * @param to the address to transfer to.
     * @param amount the amount to transfer.
     */
    function transfer(address to, uint256 amount) public override notAttached(msg.sender, amount) returns (bool) {
        return super.transfer(to, amount);
    }

    /**
     * @notice Transfers `amount` of tokens from `from` address to `to` address.
     * @dev User must have enough free boost.
     * @param from the address to transfer from.
     * @param to the address to transfer to.
     * @param amount the amount to transfer.
     */
    function transferFrom(address from, address to, uint256 amount)
        public
        override
        notAttached(from, amount)
        returns (bool)
    {
        if (from == msg.sender) return super.transfer(to, amount);

        return super.transferFrom(from, to, amount);
    }

    /*///////////////////////////////////////////////////////////////
                             MODIFIERS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Reverts if the user does not have enough free boost.
     * @param user The user address.
     * @param amount The amount of boost.
     */
    modifier notAttached(address user, uint256 amount) {
        if (freeGaugeBoost(user) < amount) revert AttachedBoost();
        _;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title  An ERC20 with an embedded attachment mechanism to keep track of boost allocations to gauges
 *  @author Maia DAO (https://github.com/Maia-DAO)
 *  @notice This contract is meant to be used to represent a token that can boost holders' rewards in other contracts.
 *          Holders can have their boost attached to gauges and cannot transfer their BurntHermes until they detach it.
 *          Only gauges can attach and detach boost from a user.
 *          The current user's boost and total supply are stored when attaching.
 *          The boost is then detached when the user removes their boost or when the gauge is removed.
 *          A "gauge" is represented by an address that distributes rewards to users periodically or continuously.
 *
 *          For example, gauges can be used to direct token emissions, similar to Curve or Hermes V1.
 *          Alternatively, gauges can be used to direct another quantity such as relative access to a line of credit.
 *          This contract should serve as reference for the amount of boost a user has allocated to a gauge.
 *          Then liquidity per user should be caculated by using this formula, from curve finance:
 *          min(UserLiquidity, (40 * UserLiquidity) + (60 * TotalLiquidity * UserBoostBalance / BoostTotal))
 *
 *          "Live" gauges are in the set.
 *          Users can only be attached to live gauges but can detach from live or deprecated gauges.
 *          Gauges can be deprecated and reinstated; and will maintain any non-removed boost from before.
 *
 *  @dev    SECURITY NOTES: decrementGaugeAllBoost can run out of gas.
 *          Gauges should be removed individually until decrementGaugeAllBoost can be called.
 *
 *          After having the boost attached:
 *           - getUserBoost() will return the maximum boost a user had allocated to all gauges.
 *             Which may be more than the current boost if there was boost removed and updateUserBoost() was not called.
 *
 *          Boost state is preserved on the gauge and user level even when a gauge is removed, in case it is re-added.
 */
interface IERC20Boost {
    /*//////////////////////////////////////////////////////////////
                                STRUCTS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice User allocated boost to a gauge and BurntHermes total supply.
     * @param userGaugeBoost User allocated boost to a gauge.
     * @param totalGaugeBoost BurntHermes total supply when a user allocated the boost.
     */
    struct GaugeState {
        uint128 userGaugeBoost;
        uint128 totalGaugeBoost;
    }

    /*///////////////////////////////////////////////////////////////
                            GAUGE STATE
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice User allocated boost to a gauge and the BurntHermes total supply.
     * @param user User address.
     * @param gauge Gauge address.
     * @return userGaugeBoost User allocated boost to a gauge.
     * @return totalGaugeBoost The BurntHermes total supply when a user allocated the boost.
     */
    function getUserGaugeBoost(address user, address gauge)
        external
        view
        returns (uint128 userGaugeBoost, uint128 totalGaugeBoost);

    /*///////////////////////////////////////////////////////////////
                            VIEW HELPERS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Maximum boost a user had allocated to all gauges since he last called decrementAllGaugesAllBoost().
     * @param user User address.
     * @return boost Maximum user allocated boost.
     */
    function getUserBoost(address user) external view returns (uint256 boost);

    /**
     * @notice returns the set of live gauges
     */
    function gauges() external view returns (address[] memory);

    /**
     * @notice returns a paginated subset of live gauges
     *   @param offset the index of the first gauge element to read
     *   @param num the number of gauges to return
     */
    function gauges(uint256 offset, uint256 num) external view returns (address[] memory values);

    /**
     * @notice returns true if `gauge` is not in deprecated gauges
     */
    function isGauge(address gauge) external view returns (bool);

    /**
     * @notice returns the number of live gauges
     */
    function numGauges() external view returns (uint256);

    /**
     * @notice returns the set of previously live but now deprecated gauges
     */
    function deprecatedGauges() external view returns (address[] memory);

    /**
     * @notice returns the number of live gauges
     */
    function numDeprecatedGauges() external view returns (uint256);

    /**
     * @notice returns the set of gauges the user has allocated to, they may be live or deprecated.
     */
    function freeGaugeBoost(address user) external view returns (uint256);

    /**
     * @notice returns the set of gauges the user has allocated to, they may be live or deprecated.
     */
    function userGauges(address user) external view returns (address[] memory);

    /**
     * @notice returns true if `gauge` is in user gauges
     */
    function isUserGauge(address user, address gauge) external view returns (bool);

    /**
     *  @notice returns a paginated subset of gauges the user has allocated to, they may be live or deprecated.
     *  @param user the user to return gauges from.
     *  @param offset the index of the first gauge element to read.
     *  @param num the number of gauges to return.
     */
    function userGauges(address user, uint256 offset, uint256 num) external view returns (address[] memory values);

    /**
     * @notice returns the number of user gauges
     */
    function numUserGauges(address user) external view returns (uint256);

    /*///////////////////////////////////////////////////////////////
                        GAUGE OPERATIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice attach all user's boost to a gauge, only callable by the gauge.
     *  @param user the user to attach the gauge to.
     */
    function attach(address user) external;

    /**
     * @notice detach all user's boost from a gauge, only callable by the gauge.
     * @param user the user to detach the gauge from.
     */
    function detach(address user) external;

    /*///////////////////////////////////////////////////////////////
                        USER GAUGE OPERATIONS
    ///////////////////////////////////////////////////////////////*/

    /**
     * @notice Update geUserBoost for a user, loop through all _userGauges
     * @param user the user to update the boost for.
     */
    function updateUserBoost(address user) external;

    /**
     * @notice Remove an amount of boost from a gauge
     * @param gauge the gauge to remove boost from.
     * @param boost the amount of boost to remove.
     */
    function decrementGaugeBoost(address gauge, uint256 boost) external;

    /**
     * @notice Remove all the boost from a gauge
     * @param gauge the gauge to remove boost from.
     */
    function decrementGaugeAllBoost(address gauge) external;

    /**
     * @notice Remove an amount of boost from all user gauges
     * @param boost the amount of boost to remove.
     */
    function decrementAllGaugesBoost(uint256 boost) external;

    /**
     * @notice Remove an amount of boost from all user gauges indexed
     * @param boost the amount of boost to remove.
     * @param offset the index of the first gauge element to read.
     * @param num the number of gauges to return.
     */
    function decrementGaugesBoostIndexed(uint256 boost, uint256 offset, uint256 num) external;

    /**
     * @notice Remove all the boost from all user gauges
     */
    function decrementAllGaugesAllBoost() external;

    /**
     * @notice add a new gauge. Requires auth by `authority`.
     */
    function addGauge(address gauge) external;

    /**
     * @notice remove a new gauge. Requires auth by `authority`.
     */
    function removeGauge(address gauge) external;

    /**
     * @notice replace a gauge. Requires auth by `authority`.
     */
    function replaceGauge(address oldGauge, address newGauge) external;

    /*///////////////////////////////////////////////////////////////
                            EVENTS
    ///////////////////////////////////////////////////////////////*/

    /// @notice emitted when adding a new gauge to the live set.
    event AddGauge(address indexed gauge);

    /// @notice emitted when removing a gauge from the live set.
    event RemoveGauge(address indexed gauge);

    /// @notice emmitted when a user attaches boost to a gauge.
    event Attach(address indexed user, address indexed gauge, uint256 indexed boost);

    /// @notice emmitted when a user detaches boost from a gauge.
    event Detach(address indexed user, address indexed gauge);

    /// @notice emmitted when a user updates their boost.
    event UpdateUserBoost(address indexed user, uint256 indexed updatedBoost);

    /// @notice emmitted when a user decrements their gauge boost.
    event DecrementUserGaugeBoost(address indexed user, address indexed gauge, uint256 indexed UpdatedBoost);

    /*///////////////////////////////////////////////////////////////
                            ERRORS
    ///////////////////////////////////////////////////////////////*/

    /// @notice thrown when trying to increment or remove a non-live gauge, or add a live gauge.
    error InvalidGauge();

    /// @notice thrown when a gauge tries to attach a position and already has one attached.
    error GaugeAlreadyAttached();

    /// @notice thrown when a gauge tries to transfer a position but does not have enough free balance.
    error AttachedBoost();
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title BurntHermes Underlying
 *  @author Maia DAO (https://github.com/Maia-DAO)
 *  @notice Represents the underlying position of the BurntHermes token.
 *   ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⡀⠀⣀⣀⠀⢀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣇⠸⣿⣿⠇⣸⣿⣿⣷⣦⣄⡀⠀⠀⠀⠀⠀⠀
 *  ⢀⣠⣴⣶⠿⠋⣩⡿⣿⡿⠻⣿⡇⢠⡄⢸⣿⠟⢿⣿⢿⣍⠙⠿⣶⣦⣄⡀⠀
 *  ⠀⠉⠉⠁⠶⠟⠋⠀⠉⠀⢀⣈⣁⡈⢁⣈⣁⡀⠀⠉⠀⠙⠻⠶⠈⠉⠉⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⡿⠛⢁⡈⠛⢿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠿⣿⣦⣤⣈⠁⢠⣴⣿⠿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢿⣿⣦⡉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢷⣦⣈⠛⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣴⠦⠈⠙⠿⣦⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⣤⡈⠁⢤⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⠑⢶⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠁⢰⡆⠈⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⠈⣡⠞⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *  ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 *
 *      ⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⠀⣼⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⠀⣿⡿⠛⠛⢿⣿⠀⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⠀⢿⠁⠀⠀⠈⡿⠀⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⣴⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀
 *      ⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⢀⣤⣄
 *      ⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣀⣀⣀⣸⣿⣿
 *      ⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
 *      ⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⢸⣿⣿
 *      ⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⡀⠀⠀⠀⠉⠁
 *      ⠀⠀⠀⣠⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⣄⠀⠀⠀
 *      ⢀⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⡀
 *      ⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿
 */
interface IbHermesUnderlying {
    /// @notice thrown when minter is not BurntHermes contract.
    error NotbHermes();

    /**
     * @notice
     */
    function bHermes() external view returns (address);

    /**
     * @notice Mints new BurntHermes underlying tokens to a specific account.
     * @param to account to transfer BurntHermes underlying tokens to
     * @param amount amount of tokens to mint.
     */
    function mint(address to, uint256 amount) external;
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AttachedBoost","type":"error"},{"inputs":[],"name":"GaugeAlreadyAttached","type":"error"},{"inputs":[],"name":"InvalidGauge","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotbHermes","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gauge","type":"address"}],"name":"AddGauge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"gauge","type":"address"},{"indexed":true,"internalType":"uint256","name":"boost","type":"uint256"}],"name":"Attach","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"gauge","type":"address"},{"indexed":true,"internalType":"uint256","name":"UpdatedBoost","type":"uint256"}],"name":"DecrementUserGaugeBoost","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"gauge","type":"address"}],"name":"Detach","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"gauge","type":"address"}],"name":"RemoveGauge","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":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"updatedBoost","type":"uint256"}],"name":"UpdateUserBoost","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"addGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"attach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bHermes","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decrementAllGaugesAllBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"boost","type":"uint256"}],"name":"decrementAllGaugesBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"decrementGaugeAllBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"},{"internalType":"uint256","name":"boost","type":"uint256"}],"name":"decrementGaugeBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"boost","type":"uint256"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"decrementGaugesBoostIndexed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deprecatedGauges","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"detach","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"freeGaugeBoost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"gauges","outputs":[{"internalType":"address[]","name":"values","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gauges","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getUserBoost","outputs":[{"internalType":"uint256","name":"boost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"gauge","type":"address"}],"name":"getUserGaugeBoost","outputs":[{"internalType":"uint128","name":"userGaugeBoost","type":"uint128"},{"internalType":"uint128","name":"totalGaugeBoost","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"gauge","type":"address"}],"name":"isGauge","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"gauge","type":"address"}],"name":"isUserGauge","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numDeprecatedGauges","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numGauges","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"numUserGauges","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"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":[{"internalType":"address","name":"gauge","type":"address"}],"name":"removeGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"oldGauge","type":"address"},{"internalType":"address","name":"newGauge","type":"address"}],"name":"replaceGauge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","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":"amount","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":"amount","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"updateUserBoost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"userGauges","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"num","type":"uint256"}],"name":"userGauges","outputs":[{"internalType":"address[]","name":"values","type":"address[]"}],"stateMutability":"view","type":"function"}]

610100604090808252346200049f57806200332f8038038091620000248285620004c0565b83396020928391810103126200049f57516001600160a01b03811691908290036200049f578251926200005784620004a4565b6011845270109d5c9b9d12195c9b595cc8109bdbdcdd607a1b828501528051916200008283620004a4565b6009835268312422a926a2a996a160b91b8184015284516001600160401b0395909390868511620004895760009480620000bd8754620004e4565b92601f9384811162000438575b508590848311600114620003d0578892620003c4575b50508160011b916000199060031b1c19161785555b815190878211620003b0578190600193620001118554620004e4565b8281116200035b575b5085918311600114620002f7578792620002eb575b5050600019600383901b1c191690821b1781555b60126080524660a052825184549181866200015e85620004e4565b9283835286830195878282169182600014620002cb5750506001146200028b575b506200018e92500382620004c0565b519020918051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452818301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019582871090871117620002775785905251902060c05281638b78c6d819557f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a33360e052612e0d908162000522823960805181611df7015260a051816123c6015260c051816123ed015260e0518181816102b20152611c9c0152f35b634e487b7160e01b84526041600452602484fd5b8691508880528189209089915b858310620002b25750506200018e9350820101386200017f565b8054838801850152869450889390920191810162000298565b60ff191688526200018e95151560051b85010192503891506200017f9050565b0151905038806200012f565b8488528588208594509190601f198416895b888282106200034457505084116200032a575b505050811b01815562000143565b015160001960f88460031b161c191690553880806200031c565b838501518655889790950194938401930162000309565b909192508488528588208380860160051c820192888710620003a6575b91869588929594930160051c01915b828110620003975750506200011a565b8a815586955087910162000387565b9250819262000378565b634e487b7160e01b86526041600452602486fd5b015190503880620000e0565b8880528689209250601f198416895b888282106200042157505090846001959493921062000407575b505050811b018555620000f5565b015160001960f88460031b161c19169055388080620003f9565b6001859682939686015181550195019301620003df565b9091508780528588208480850160051c8201928886106200047f575b9085949392910160051c01905b818110620004705750620000ca565b89815584935060010162000461565b9250819262000454565b634e487b7160e01b600052604160045260246000fd5b600080fd5b604081019081106001600160401b038211176200048957604052565b601f909101601f19168101906001600160401b038211908210176200048957604052565b90600182811c9216801562000516575b60208310146200050057565b634e487b7160e01b600052602260045260246000fd5b91607f1691620004f456fe608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde031461210057508163095ea7b31461206557816318160ddd146120285781631c2a2e3114611f9057816323b872dd14611f0557816324b78cbc14611ec15781632569296214611e58578163260fd97014611e1b578163313ce56714611dbf5781633644e51514611d7d5781633a04514514611d3a57816340c10f1914611c46578163481436c214611b0e578163488bec8914611aac57816354d1f13d14611a485781635a1994c41461195e57816364cb685a1461192157816370a08231146118bf578163715018a6146118405781637a0ca1e21461166e5781637ecebe001461160c578163817c3b131461156d578163821bdcf1146114cb57816384e60a1a1461138b5781638da5cb5b146113195781639487a2fa146112c65781639581372b1461126457816395d89b411461114d578163969b12681461109c5781639da882ac14611051578163a9059cbb14610fd1578163aa79979b14610f51578163b233355414610ec1578163cd4973ce14610e19578163ceb6c34314610d71578163d232681e14610c0d578163d505accf14610912578163dd62ed3e1461089e578163e4b79db9146106b4578163e9726524146104db578163eb00529e14610453578163f04e283e1461038a578163f2fde38b146102d657508063fa7e38da146102685763fee81cf41461021457600080fd5b346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645760209161024e6122ed565b9063389a75e1600c525281600c20549051908152f35b5080fd5b503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b839060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645761030a6122ed565b90610313612389565b8160601b1561037f575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a35580f35b637448fbae8352601cfd5b8360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576103bd6122ed565b6103c5612389565b63389a75e1600c528082526020600c20928354421161044557508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a35580f35b636f5e88188352601cfd5b80fd5b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576104d26020926104916122ed565b8361049a612315565b9273ffffffffffffffffffffffffffffffffffffffff8093168152600887522091169060019160005201602052604060002054151590565b90519015158152f35b8391503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b0573591338152600882528381209182549385518281878152018585528184862091865b868a821061069a57505061054792500382612217565b8051845b87811080610691575b1561068d5773ffffffffffffffffffffffffffffffffffffffff6105788285612605565b511633875260068087528a882082895287528a8089208054886fffffffffffffffffffffffffffffffff9384831690600c8d528d205415801590610683575b156106175750505050506105cb828a612a4f565b1561061357906001929133895287528a88208189528752878b812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58980a35b0161054b565b8780fd5b600197969495507fffffffffffffffffffffffffffffffff000000000000000000000000000000009161064991612697565b94610653866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458a80a461060d565b50808210156105b7565b8580f35b50818110610554565b8454835260019485019486945092019101610531565b8280fd5b839150346102645760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264573590602435906044359233825260209060088252858320938651908182858854928381520188885286882092885b888282106108885750505061072b92500383612217565b8151855b8881108061087f575b1561087b5773ffffffffffffffffffffffffffffffffffffffff61076561075f8386612ba8565b86612605565b511633885260068088528b8920828a528852888c81208d898b8354926fffffffffffffffffffffffffffffffff95600c8786169352205415801590610871575b156108055750505050506107b9828b612a4f565b15610801579060019291338a5288528b8920818a528852888c812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58a80a35b0161072f565b8880fd5b600197969495507fffffffffffffffffffffffffffffffff000000000000000000000000000000009161083791612697565b94610841866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458b80a46107fb565b50808210156107a5565b8680f35b50818110610738565b8554845260019586019588955093019201610714565b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05760209282916108db6122ed565b6108e3612315565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8383346102645760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645761094b6122ed565b90610954612315565b91604435606435926084359260ff8416809403610c0957428510610bac5761097a6123c1565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff9484821086831117610b7f57818852845190206101008501927f190100000000000000000000000000000000000000000000000000000000000084526101028601526101228501526042815261016084019481861090861117610b5357848752519020835261018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa15610b49578651169687151580610b40575b15610ae55786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b50848814610aa2565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8680fd5b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645781610c466122ed565b916024353383526020906006825273ffffffffffffffffffffffffffffffffffffffff838520951694858552825282842080546fffffffffffffffffffffffffffffffff92838216600c86528688205415801590610d67575b15610cfb57505050505033835260088152610cbc84838520612a4f565b156106b057338352600681528183209084845252812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b909194507fffffffffffffffffffffffffffffffff0000000000000000000000000000000093979650610d2f929550612697565b94610d39866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458480a480f35b5080821015610c9f565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578173ffffffffffffffffffffffffffffffffffffffff610dc06122ed565b16918282526008602052610dd78183203390612a4f565b1561026457828252600660205280822033835260205281205533907ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645781610e536122ed565b913382526008602052610e8073ffffffffffffffffffffffffffffffffffffffff82842094168094612a4f565b15610264573382526006602052808220838352602052812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578091610efb6122ed565b610f03612315565b9073ffffffffffffffffffffffffffffffffffffffff809116835260066020528383209116825260205220548151906fffffffffffffffffffffffffffffffff8116825260801c6020820152f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264579060209173ffffffffffffffffffffffffffffffffffffffff610fa36122ed565b168252600a83528082205415159182610fc0575b50519015158152f35b819250600c84522054159038610fb7565b82843461045057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450575061100a6122ed565b6024359283611018336126d3565b1061102a57506020926104d291612c9a565b82517f10f6e63b000000000000000000000000000000000000000000000000000000008152fd5b83346104505760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505761109961108c6122ed565b611094612389565b612bb5565b80f35b8284346104505760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576110d56122ed565b9060243591604435916110e7836125b6565b9373ffffffffffffffffffffffffffffffffffffffff80931682526008602052858220915b848110611124578651806111208882612338565b0390f35b808461113460019385018661267f565b90549060031b1c166111468289612605565b520161110c565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645780519082600180549161118f836121c4565b8086529282811690811561121e57506001146111c2575b5050506111b882611120940383612217565b5191829182612287565b94508085527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828610611206575050506111b882602061112095820101946111a6565b805460208787018101919091529095019481016111e9565b6111209750869350602092506111b89491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101946111a6565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff6112b66122ed565b1681526007845220549051908152f35b505034610264577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576110996113006122ed565b61109461130b612315565b91611314612389565b612c4f565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b50503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b057906113c76122ed565b908392839173ffffffffffffffffffffffffffffffffffffffff8094169384875260088252828720835190818482549182815201918a52848a20908a5b8181106114b4575050508161141a910382612217565b805191885b83811061145b5750505050600790848752528420557f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438380a380f35b9091929394955086895260068552858920826114778386612605565b51168a5285526fffffffffffffffffffffffffffffffff868a2054168089106114ab575b506001019291908795949361141f565b9750600161149b565b825484528a98509286019260019283019201611404565b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450578151918291600954808552602080950194600983527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af92905b82821061155657611120868661154c828b0383612217565b5191829182612338565b835487529586019560019384019390910190611534565b50503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05773ffffffffffffffffffffffffffffffffffffffff6115bd6122ed565b168352600882528083209281518093808654928381520195835280832092905b8282106115f557611120868661154c828b0383612217565b8354875295860195600193840193909101906115dd565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff61165e6122ed565b1681526005845220549051908152f35b9050346106b0576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261183c576116a86122ed565b338552600a82528385205415801561182c575b6118045773ffffffffffffffffffffffffffffffffffffffff1691828552600882526116e933858720612864565b156117dd575081845260038152611702838520546128c0565b9282855260078252808520936fffffffffffffffffffffffffffffffff8554911694858092106117af575b50506002549182611765575b50505033907f60940192810a6fb3bce3fd3e2e3a13fd6ccc7605e963fb87ee971aba829989bd8480a480f35b7fffffffffffffffffffffffffffffffff000000000000000000000000000000009181600661179f935281882090338952528620926128c0565b60801b1683179055388080611739565b5583837f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438780a3833861172d565b83517faeccd4da000000000000000000000000000000000000000000000000000000008152fd5b8284517fcbb4b772000000000000000000000000000000000000000000000000000000008152fd5b50600c82528385205415156116bb565b8380fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261045057611872612389565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff6119116122ed565b1681526003845220549051908152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090600b549051908152f35b919050346106b057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05781929135916024928335916119a3836125b6565b9481966009938454985b8681106119c1578751806111208b82612338565b8082018a811015611a1d579073ffffffffffffffffffffffffffffffffffffffff6001928888527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af015416611a16828c612605565b52016119ad565b84866032867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff611afe6122ed565b1681526008845220549051908152f35b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450573381526020916008835280822090805193849281815496878152019581865282862090865b818110611c3257505050611b7d8486979695960386612217565b845194845b868110611bbf578580866007873384525281205580337f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438280a380f35b73ffffffffffffffffffffffffffffffffffffffff611bde8284612605565b511690611beb8285612a4f565b15610c09576001913388526006865286882081895286528787812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58980a301611b82565b825489529784019760019283019201611b63565b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b057611c7e6122ed565b906024359173ffffffffffffffffffffffffffffffffffffffff91827f0000000000000000000000000000000000000000000000000000000000000000163303611d135750827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092611cf68896600254612ba8565b60025516948585526003835280852082815401905551908152a380f35b84517f4d316367000000000000000000000000000000000000000000000000000000008152fd5b83346104505760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261045057611099611d756122ed565b611314612389565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090611db86123c1565b9051908152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020905160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020906009549051908152f35b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090611db8611f006122ed565b6126d3565b8284346104505760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505750611f3f6122ed565b611f47612315565b906044359384611f56836126d3565b10611f695750926104d291602094612d12565b83517f10f6e63b000000000000000000000000000000000000000000000000000000008152fd5b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450578151918291600b54808552602080950194600b83527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db992905b82821061201157611120868661154c828b0383612217565b835487529586019560019384019390910190611ff9565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020906002549051908152f35b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b0576020926120a06122ed565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b849084346106b057827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05782805461213d816121c4565b8085529160019180831690811561121e5750600114612168575050506111b882611120940383612217565b80809650527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8286106121ac575050506111b882602061112095820101946111a6565b8054602087870181019190915290950194810161218f565b90600182811c9216801561220d575b60208310146121de57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916121d3565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761225857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60208082528251818301819052939260005b8581106122d9575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201612299565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361231057565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361231057565b6020908160408183019282815285518094520193019160005b82811061235f575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101612351565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433036123b357565b6382b429006000526004601cfd5b6000467f00000000000000000000000000000000000000000000000000000000000000000361240f57507f000000000000000000000000000000000000000000000000000000000000000090565b6040518154829161241f826121c4565b8082528160209485820194600190878282169182600014612562575050600114612509575b5061245192500382612217565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff8311176124dc575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061254a575050612451935082010138612444565b80548388018501528694508893909201918101612533565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016885261245195151560051b85010192503891506124449050565b67ffffffffffffffff81116122585760051b60200190565b906125c08261259e565b6125cd6040519182612217565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06125fb829461259e565b0190602036910137565b80518210156126195760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600b5481101561261957600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90190600090565b80548210156126195760005260206000200190600090565b919082039182116126a457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff16600052600360205261270b604060002054600760205260406000205490612697565b90565b6000818152600a60205260408120546127d857600954680100000000000000008110156127ab57600181018060095581101561277e5790826040927f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155600954928152600a6020522055600190565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905090565b6000818152600c60205260408120546127d857600b54680100000000000000008110156127ab57908261285061281b84600160409601600b55612648565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b9055600b54928152600c6020522055600190565b60008281526001820160205260409020546128b9578054906801000000000000000082101561225857826128a261281b84600180960185558461267f565b905580549260005201602052604060002055600190565b5050600090565b7001000000000000000000000000000000008110156128ee576fffffffffffffffffffffffffffffffff1690565b6335278d126000526004601cfd5b6000818152600c60205260408120549091908015612a4a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90818101818111612a1d57600b54908382019182116129f0578082036129bc575b505050600b54801561298f5781019061296e82612648565b909182549160031b1b19169055600b558152600c6020526040812055600190565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b6129da6129cb61281b93612648565b90549060031b1c928392612648565b90558452600c6020526040842055388080612956565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505090565b90600182019060009281845282602052604084205490811515600014612ba1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91828101818111612b7457825490848201918211612b4757808203612b12575b50505080548015612ae557820191612ac8838361267f565b909182549160031b1b191690555582526020526040812055600190565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b612b32612b2261281b938661267f565b90549060031b1c9283928661267f565b90558652846020526040862055388080612ab0565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b5050505090565b919082018092116126a457565b73ffffffffffffffffffffffffffffffffffffffff1680158015612c29575b612bff577f663bc5df9b13d61c4a5b97abcf8e3f327c80b0ee0c0db02c66536fe30399afab600080a2565b60046040517fcbb4b772000000000000000000000000000000000000000000000000000000008152fd5b50612c338161270e565b8015612c40575b15612bd4565b50612c4a816128fc565b612c3a565b73ffffffffffffffffffffffffffffffffffffffff16612c6e816127dd565b15612bff577fd8447e2a6ccc1f3caeea39fdaea6ca5c1c22a9ab79022d1e39a8c24f0736e549600080a2565b73ffffffffffffffffffffffffffffffffffffffff903360005260036020526040600020612cc9848254612697565b9055169081600052600360205260406000208181540190556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3600190565b919073ffffffffffffffffffffffffffffffffffffffff80931691338314612df457907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91600094848652602092600484526040918291828920338a52865282892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd1575b505087895260038652828920612db5868254612697565b90551696878152600385522082815401905551908152a3600190565b612dda91612697565b888a5260048752838a20338b528752838a20553885612d9e565b915061270b9250612c9a56fea164736f6c6343000813000a00000000000000000000000000000000206ad3e31dfff979ccef06de72a9e027

Deployed Bytecode

0x608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde031461210057508163095ea7b31461206557816318160ddd146120285781631c2a2e3114611f9057816323b872dd14611f0557816324b78cbc14611ec15781632569296214611e58578163260fd97014611e1b578163313ce56714611dbf5781633644e51514611d7d5781633a04514514611d3a57816340c10f1914611c46578163481436c214611b0e578163488bec8914611aac57816354d1f13d14611a485781635a1994c41461195e57816364cb685a1461192157816370a08231146118bf578163715018a6146118405781637a0ca1e21461166e5781637ecebe001461160c578163817c3b131461156d578163821bdcf1146114cb57816384e60a1a1461138b5781638da5cb5b146113195781639487a2fa146112c65781639581372b1461126457816395d89b411461114d578163969b12681461109c5781639da882ac14611051578163a9059cbb14610fd1578163aa79979b14610f51578163b233355414610ec1578163cd4973ce14610e19578163ceb6c34314610d71578163d232681e14610c0d578163d505accf14610912578163dd62ed3e1461089e578163e4b79db9146106b4578163e9726524146104db578163eb00529e14610453578163f04e283e1461038a578163f2fde38b146102d657508063fa7e38da146102685763fee81cf41461021457600080fd5b346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645760209161024e6122ed565b9063389a75e1600c525281600c20549051908152f35b5080fd5b503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020905173ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000066ea454672f4733407a74b886d3c93168152f35b839060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645761030a6122ed565b90610313612389565b8160601b1561037f575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a35580f35b637448fbae8352601cfd5b8360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576103bd6122ed565b6103c5612389565b63389a75e1600c528082526020600c20928354421161044557508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a35580f35b636f5e88188352601cfd5b80fd5b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576104d26020926104916122ed565b8361049a612315565b9273ffffffffffffffffffffffffffffffffffffffff8093168152600887522091169060019160005201602052604060002054151590565b90519015158152f35b8391503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b0573591338152600882528381209182549385518281878152018585528184862091865b868a821061069a57505061054792500382612217565b8051845b87811080610691575b1561068d5773ffffffffffffffffffffffffffffffffffffffff6105788285612605565b511633875260068087528a882082895287528a8089208054886fffffffffffffffffffffffffffffffff9384831690600c8d528d205415801590610683575b156106175750505050506105cb828a612a4f565b1561061357906001929133895287528a88208189528752878b812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58980a35b0161054b565b8780fd5b600197969495507fffffffffffffffffffffffffffffffff000000000000000000000000000000009161064991612697565b94610653866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458a80a461060d565b50808210156105b7565b8580f35b50818110610554565b8454835260019485019486945092019101610531565b8280fd5b839150346102645760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264573590602435906044359233825260209060088252858320938651908182858854928381520188885286882092885b888282106108885750505061072b92500383612217565b8151855b8881108061087f575b1561087b5773ffffffffffffffffffffffffffffffffffffffff61076561075f8386612ba8565b86612605565b511633885260068088528b8920828a528852888c81208d898b8354926fffffffffffffffffffffffffffffffff95600c8786169352205415801590610871575b156108055750505050506107b9828b612a4f565b15610801579060019291338a5288528b8920818a528852888c812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58a80a35b0161072f565b8880fd5b600197969495507fffffffffffffffffffffffffffffffff000000000000000000000000000000009161083791612697565b94610841866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458b80a46107fb565b50808210156107a5565b8680f35b50818110610738565b8554845260019586019588955093019201610714565b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05760209282916108db6122ed565b6108e3612315565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8383346102645760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645761094b6122ed565b90610954612315565b91604435606435926084359260ff8416809403610c0957428510610bac5761097a6123c1565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff9484821086831117610b7f57818852845190206101008501927f190100000000000000000000000000000000000000000000000000000000000084526101028601526101228501526042815261016084019481861090861117610b5357848752519020835261018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa15610b49578651169687151580610b40575b15610ae55786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b50848814610aa2565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8680fd5b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645781610c466122ed565b916024353383526020906006825273ffffffffffffffffffffffffffffffffffffffff838520951694858552825282842080546fffffffffffffffffffffffffffffffff92838216600c86528688205415801590610d67575b15610cfb57505050505033835260088152610cbc84838520612a4f565b156106b057338352600681528183209084845252812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b909194507fffffffffffffffffffffffffffffffff0000000000000000000000000000000093979650610d2f929550612697565b94610d39866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458480a480f35b5080821015610c9f565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578173ffffffffffffffffffffffffffffffffffffffff610dc06122ed565b16918282526008602052610dd78183203390612a4f565b1561026457828252600660205280822033835260205281205533907ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645781610e536122ed565b913382526008602052610e8073ffffffffffffffffffffffffffffffffffffffff82842094168094612a4f565b15610264573382526006602052808220838352602052812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578091610efb6122ed565b610f03612315565b9073ffffffffffffffffffffffffffffffffffffffff809116835260066020528383209116825260205220548151906fffffffffffffffffffffffffffffffff8116825260801c6020820152f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264579060209173ffffffffffffffffffffffffffffffffffffffff610fa36122ed565b168252600a83528082205415159182610fc0575b50519015158152f35b819250600c84522054159038610fb7565b82843461045057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450575061100a6122ed565b6024359283611018336126d3565b1061102a57506020926104d291612c9a565b82517f10f6e63b000000000000000000000000000000000000000000000000000000008152fd5b83346104505760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505761109961108c6122ed565b611094612389565b612bb5565b80f35b8284346104505760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576110d56122ed565b9060243591604435916110e7836125b6565b9373ffffffffffffffffffffffffffffffffffffffff80931682526008602052858220915b848110611124578651806111208882612338565b0390f35b808461113460019385018661267f565b90549060031b1c166111468289612605565b520161110c565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645780519082600180549161118f836121c4565b8086529282811690811561121e57506001146111c2575b5050506111b882611120940383612217565b5191829182612287565b94508085527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828610611206575050506111b882602061112095820101946111a6565b805460208787018101919091529095019481016111e9565b6111209750869350602092506111b89491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101946111a6565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff6112b66122ed565b1681526007845220549051908152f35b505034610264577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576110996113006122ed565b61109461130b612315565b91611314612389565b612c4f565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b50503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b057906113c76122ed565b908392839173ffffffffffffffffffffffffffffffffffffffff8094169384875260088252828720835190818482549182815201918a52848a20908a5b8181106114b4575050508161141a910382612217565b805191885b83811061145b5750505050600790848752528420557f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438380a380f35b9091929394955086895260068552858920826114778386612605565b51168a5285526fffffffffffffffffffffffffffffffff868a2054168089106114ab575b506001019291908795949361141f565b9750600161149b565b825484528a98509286019260019283019201611404565b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450578151918291600954808552602080950194600983527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af92905b82821061155657611120868661154c828b0383612217565b5191829182612338565b835487529586019560019384019390910190611534565b50503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05773ffffffffffffffffffffffffffffffffffffffff6115bd6122ed565b168352600882528083209281518093808654928381520195835280832092905b8282106115f557611120868661154c828b0383612217565b8354875295860195600193840193909101906115dd565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff61165e6122ed565b1681526005845220549051908152f35b9050346106b0576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261183c576116a86122ed565b338552600a82528385205415801561182c575b6118045773ffffffffffffffffffffffffffffffffffffffff1691828552600882526116e933858720612864565b156117dd575081845260038152611702838520546128c0565b9282855260078252808520936fffffffffffffffffffffffffffffffff8554911694858092106117af575b50506002549182611765575b50505033907f60940192810a6fb3bce3fd3e2e3a13fd6ccc7605e963fb87ee971aba829989bd8480a480f35b7fffffffffffffffffffffffffffffffff000000000000000000000000000000009181600661179f935281882090338952528620926128c0565b60801b1683179055388080611739565b5583837f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438780a3833861172d565b83517faeccd4da000000000000000000000000000000000000000000000000000000008152fd5b8284517fcbb4b772000000000000000000000000000000000000000000000000000000008152fd5b50600c82528385205415156116bb565b8380fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261045057611872612389565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff6119116122ed565b1681526003845220549051908152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090600b549051908152f35b919050346106b057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05781929135916024928335916119a3836125b6565b9481966009938454985b8681106119c1578751806111208b82612338565b8082018a811015611a1d579073ffffffffffffffffffffffffffffffffffffffff6001928888527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af015416611a16828c612605565b52016119ad565b84866032867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff611afe6122ed565b1681526008845220549051908152f35b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450573381526020916008835280822090805193849281815496878152019581865282862090865b818110611c3257505050611b7d8486979695960386612217565b845194845b868110611bbf578580866007873384525281205580337f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438280a380f35b73ffffffffffffffffffffffffffffffffffffffff611bde8284612605565b511690611beb8285612a4f565b15610c09576001913388526006865286882081895286528787812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58980a301611b82565b825489529784019760019283019201611b63565b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b057611c7e6122ed565b906024359173ffffffffffffffffffffffffffffffffffffffff91827f000000000000000000000000000000000066ea454672f4733407a74b886d3c93163303611d135750827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092611cf68896600254612ba8565b60025516948585526003835280852082815401905551908152a380f35b84517f4d316367000000000000000000000000000000000000000000000000000000008152fd5b83346104505760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261045057611099611d756122ed565b611314612389565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090611db86123c1565b9051908152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020905160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020906009549051908152f35b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090611db8611f006122ed565b6126d3565b8284346104505760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505750611f3f6122ed565b611f47612315565b906044359384611f56836126d3565b10611f695750926104d291602094612d12565b83517f10f6e63b000000000000000000000000000000000000000000000000000000008152fd5b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450578151918291600b54808552602080950194600b83527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db992905b82821061201157611120868661154c828b0383612217565b835487529586019560019384019390910190611ff9565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020906002549051908152f35b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b0576020926120a06122ed565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b849084346106b057827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05782805461213d816121c4565b8085529160019180831690811561121e5750600114612168575050506111b882611120940383612217565b80809650527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8286106121ac575050506111b882602061112095820101946111a6565b8054602087870181019190915290950194810161218f565b90600182811c9216801561220d575b60208310146121de57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916121d3565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761225857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60208082528251818301819052939260005b8581106122d9575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201612299565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361231057565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361231057565b6020908160408183019282815285518094520193019160005b82811061235f575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101612351565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433036123b357565b6382b429006000526004601cfd5b6000467f000000000000000000000000000000000000000000000000000000000000a4b10361240f57507fb0315e76b3e6159093155974ef539e0c6816e7c3b135e434a98654d6cbf9030f90565b6040518154829161241f826121c4565b8082528160209485820194600190878282169182600014612562575050600114612509575b5061245192500382612217565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff8311176124dc575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061254a575050612451935082010138612444565b80548388018501528694508893909201918101612533565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016885261245195151560051b85010192503891506124449050565b67ffffffffffffffff81116122585760051b60200190565b906125c08261259e565b6125cd6040519182612217565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06125fb829461259e565b0190602036910137565b80518210156126195760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600b5481101561261957600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90190600090565b80548210156126195760005260206000200190600090565b919082039182116126a457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff16600052600360205261270b604060002054600760205260406000205490612697565b90565b6000818152600a60205260408120546127d857600954680100000000000000008110156127ab57600181018060095581101561277e5790826040927f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155600954928152600a6020522055600190565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905090565b6000818152600c60205260408120546127d857600b54680100000000000000008110156127ab57908261285061281b84600160409601600b55612648565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b9055600b54928152600c6020522055600190565b60008281526001820160205260409020546128b9578054906801000000000000000082101561225857826128a261281b84600180960185558461267f565b905580549260005201602052604060002055600190565b5050600090565b7001000000000000000000000000000000008110156128ee576fffffffffffffffffffffffffffffffff1690565b6335278d126000526004601cfd5b6000818152600c60205260408120549091908015612a4a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90818101818111612a1d57600b54908382019182116129f0578082036129bc575b505050600b54801561298f5781019061296e82612648565b909182549160031b1b19169055600b558152600c6020526040812055600190565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b6129da6129cb61281b93612648565b90549060031b1c928392612648565b90558452600c6020526040842055388080612956565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505090565b90600182019060009281845282602052604084205490811515600014612ba1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91828101818111612b7457825490848201918211612b4757808203612b12575b50505080548015612ae557820191612ac8838361267f565b909182549160031b1b191690555582526020526040812055600190565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b612b32612b2261281b938661267f565b90549060031b1c9283928661267f565b90558652846020526040862055388080612ab0565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b5050505090565b919082018092116126a457565b73ffffffffffffffffffffffffffffffffffffffff1680158015612c29575b612bff577f663bc5df9b13d61c4a5b97abcf8e3f327c80b0ee0c0db02c66536fe30399afab600080a2565b60046040517fcbb4b772000000000000000000000000000000000000000000000000000000008152fd5b50612c338161270e565b8015612c40575b15612bd4565b50612c4a816128fc565b612c3a565b73ffffffffffffffffffffffffffffffffffffffff16612c6e816127dd565b15612bff577fd8447e2a6ccc1f3caeea39fdaea6ca5c1c22a9ab79022d1e39a8c24f0736e549600080a2565b73ffffffffffffffffffffffffffffffffffffffff903360005260036020526040600020612cc9848254612697565b9055169081600052600360205260406000208181540190556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3600190565b919073ffffffffffffffffffffffffffffffffffffffff80931691338314612df457907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91600094848652602092600484526040918291828920338a52865282892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd1575b505087895260038652828920612db5868254612697565b90551696878152600385522082815401905551908152a3600190565b612dda91612697565b888a5260048752838a20338b528752838a20553885612d9e565b915061270b9250612c9a56fea164736f6c6343000813000a

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

00000000000000000000000000000000206ad3e31dfff979ccef06de72a9e027

-----Decoded View---------------
Arg [0] : _owner (address): 0x00000000206ad3e31DffF979Ccef06dE72a9E027

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000206ad3e31dfff979ccef06de72a9e027


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.