Sepolia Testnet

Contract

0xE2eaCd92208E81c88E629682aeab5646E4f8ed69

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Approve71010172024-11-18 7:50:2461 days ago1731916224IN
0xE2eaCd92...6E4f8ed69
0 ETH0.000068921.50105384
Approve70415862024-11-09 8:49:4870 days ago1731142188IN
0xE2eaCd92...6E4f8ed69
0 ETH0.0006491114.13538136
Approve65045432024-08-15 11:02:24156 days ago1723719744IN
0xE2eaCd92...6E4f8ed69
0 ETH0.000209274.53232011
Approve63689152024-07-24 18:05:12178 days ago1721844312IN
0xE2eaCd92...6E4f8ed69
0 ETH0.0008498718.49776528
Transfer Ownersh...63298102024-07-17 22:21:00184 days ago1721254860IN
0xE2eaCd92...6E4f8ed69
0 ETH0.00004391.50097957
Transfer Ownersh...63298012024-07-17 22:19:00184 days ago1721254740IN
0xE2eaCd92...6E4f8ed69
0 ETH0.00004391.5009071
Transfer Ownersh...63296112024-07-17 21:32:00184 days ago1721251920IN
0xE2eaCd92...6E4f8ed69
0 ETH0.00004391.50079175

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
63268222024-07-17 10:30:12185 days ago1721212212  Contract Creation0 ETH
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x1A17c9Ca...c957ead6a
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
bHermesBoost

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 8 : bHermesBoost.sol
// 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();
        _;
    }
}

File 2 of 8 : EnumerableSet.sol
// 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;
    }
}

File 3 of 8 : Ownable.sol
// 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)
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) {
        int8 y = int8(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt16(int256 x) internal pure returns (int16) {
        int16 y = int16(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt24(int256 x) internal pure returns (int24) {
        int24 y = int24(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt32(int256 x) internal pure returns (int32) {
        int32 y = int32(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt40(int256 x) internal pure returns (int40) {
        int40 y = int40(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt48(int256 x) internal pure returns (int48) {
        int48 y = int48(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt56(int256 x) internal pure returns (int56) {
        int56 y = int56(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt64(int256 x) internal pure returns (int64) {
        int64 y = int64(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt72(int256 x) internal pure returns (int72) {
        int72 y = int72(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt80(int256 x) internal pure returns (int80) {
        int80 y = int80(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt88(int256 x) internal pure returns (int88) {
        int88 y = int88(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt96(int256 x) internal pure returns (int96) {
        int96 y = int96(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt104(int256 x) internal pure returns (int104) {
        int104 y = int104(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt112(int256 x) internal pure returns (int112) {
        int112 y = int112(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt120(int256 x) internal pure returns (int120) {
        int120 y = int120(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt128(int256 x) internal pure returns (int128) {
        int128 y = int128(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt136(int256 x) internal pure returns (int136) {
        int136 y = int136(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt144(int256 x) internal pure returns (int144) {
        int144 y = int144(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt152(int256 x) internal pure returns (int152) {
        int152 y = int152(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt160(int256 x) internal pure returns (int160) {
        int160 y = int160(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt168(int256 x) internal pure returns (int168) {
        int168 y = int168(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt176(int256 x) internal pure returns (int176) {
        int176 y = int176(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt184(int256 x) internal pure returns (int184) {
        int184 y = int184(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt192(int256 x) internal pure returns (int192) {
        int192 y = int192(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt200(int256 x) internal pure returns (int200) {
        int200 y = int200(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt208(int256 x) internal pure returns (int208) {
        int208 y = int208(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt216(int256 x) internal pure returns (int216) {
        int216 y = int216(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt224(int256 x) internal pure returns (int224) {
        int224 y = int224(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt232(int256 x) internal pure returns (int232) {
        int232 y = int232(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt240(int256 x) internal pure returns (int240) {
        int240 y = int240(x);
        if (x != y) _revertOverflow();
        return y;
    }

    function toInt248(int256 x) internal pure returns (int248) {
        int248 y = int248(x);
        if (x != y) _revertOverflow();
        return y;
    }

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

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

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

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      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)
        }
    }
}

File 5 of 8 : ERC20.sol
// 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);
    }
}

File 6 of 8 : ERC20Boost.sol
// 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();
        _;
    }
}

File 7 of 8 : IERC20Boost.sol
// 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();
}

File 8 of 8 : IbHermesUnderlying.sol
// 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 ABI

[{"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"}]

Deployed Bytecode

0x608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde031461210057508163095ea7b31461206557816318160ddd146120285781631c2a2e3114611f9057816323b872dd14611f0557816324b78cbc14611ec15781632569296214611e58578163260fd97014611e1b578163313ce56714611dbf5781633644e51514611d7d5781633a04514514611d3a57816340c10f1914611c46578163481436c214611b0e578163488bec8914611aac57816354d1f13d14611a485781635a1994c41461195e57816364cb685a1461192157816370a08231146118bf578163715018a6146118405781637a0ca1e21461166e5781637ecebe001461160c578163817c3b131461156d578163821bdcf1146114cb57816384e60a1a1461138b5781638da5cb5b146113195781639487a2fa146112c65781639581372b1461126457816395d89b411461114d578163969b12681461109c5781639da882ac14611051578163a9059cbb14610fd1578163aa79979b14610f51578163b233355414610ec1578163cd4973ce14610e19578163ceb6c34314610d71578163d232681e14610c0d578163d505accf14610912578163dd62ed3e1461089e578163e4b79db9146106b4578163e9726524146104db578163eb00529e14610453578163f04e283e1461038a578163f2fde38b146102d657508063fa7e38da146102685763fee81cf41461021457600080fd5b346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645760209161024e6122ed565b9063389a75e1600c525281600c20549051908152f35b5080fd5b503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020905173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000012bce9dbffd8f20b1b7f74c9a5678f770fcb36b8168152f35b839060207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645761030a6122ed565b90610313612389565b8160601b1561037f575073ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a35580f35b637448fbae8352601cfd5b8360207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576103bd6122ed565b6103c5612389565b63389a75e1600c528082526020600c20928354421161044557508173ffffffffffffffffffffffffffffffffffffffff929355167fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a35580f35b636f5e88188352601cfd5b80fd5b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576104d26020926104916122ed565b8361049a612315565b9273ffffffffffffffffffffffffffffffffffffffff8093168152600887522091169060019160005201602052604060002054151590565b90519015158152f35b8391503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b0573591338152600882528381209182549385518281878152018585528184862091865b868a821061069a57505061054792500382612217565b8051845b87811080610691575b1561068d5773ffffffffffffffffffffffffffffffffffffffff6105788285612605565b511633875260068087528a882082895287528a8089208054886fffffffffffffffffffffffffffffffff9384831690600c8d528d205415801590610683575b156106175750505050506105cb828a612a4f565b1561061357906001929133895287528a88208189528752878b812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58980a35b0161054b565b8780fd5b600197969495507fffffffffffffffffffffffffffffffff000000000000000000000000000000009161064991612697565b94610653866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458a80a461060d565b50808210156105b7565b8580f35b50818110610554565b8454835260019485019486945092019101610531565b8280fd5b839150346102645760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264573590602435906044359233825260209060088252858320938651908182858854928381520188885286882092885b888282106108885750505061072b92500383612217565b8151855b8881108061087f575b1561087b5773ffffffffffffffffffffffffffffffffffffffff61076561075f8386612ba8565b86612605565b511633885260068088528b8920828a528852888c81208d898b8354926fffffffffffffffffffffffffffffffff95600c8786169352205415801590610871575b156108055750505050506107b9828b612a4f565b15610801579060019291338a5288528b8920818a528852888c812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58a80a35b0161072f565b8880fd5b600197969495507fffffffffffffffffffffffffffffffff000000000000000000000000000000009161083791612697565b94610841866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458b80a46107fb565b50808210156107a5565b8680f35b50818110610738565b8554845260019586019588955093019201610714565b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05760209282916108db6122ed565b6108e3612315565b9173ffffffffffffffffffffffffffffffffffffffff8092168452865283832091168252845220549051908152f35b8383346102645760e07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645761094b6122ed565b90610954612315565b91604435606435926084359260ff8416809403610c0957428510610bac5761097a6123c1565b9573ffffffffffffffffffffffffffffffffffffffff8092169586895260209560058752848a209889549960018b01905585519285898501957f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c987528b89870152169a8b606086015288608086015260a085015260c084015260c0835260e0830167ffffffffffffffff9484821086831117610b7f57818852845190206101008501927f190100000000000000000000000000000000000000000000000000000000000084526101028601526101228501526042815261016084019481861090861117610b5357848752519020835261018082015260a4356101a082015260c4356101c0909101528780528490889060809060015afa15610b49578651169687151580610b40575b15610ae55786977f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259596975283528087208688528352818188205551908152a380f35b8360649251917f08c379a0000000000000000000000000000000000000000000000000000000008352820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152fd5b50848814610aa2565b81513d88823e3d90fd5b60248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5060248c60418f7f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b60648860208451917f08c379a0000000000000000000000000000000000000000000000000000000008352820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152fd5b8680fd5b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645781610c466122ed565b916024353383526020906006825273ffffffffffffffffffffffffffffffffffffffff838520951694858552825282842080546fffffffffffffffffffffffffffffffff92838216600c86528688205415801590610d67575b15610cfb57505050505033835260088152610cbc84838520612a4f565b156106b057338352600681528183209084845252812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b909194507fffffffffffffffffffffffffffffffff0000000000000000000000000000000093979650610d2f929550612697565b94610d39866128c0565b169116179055337fb6c49cb8119cb7b6dfab8e3d72115a2774a3aa5c515a2c8fba7130492c176b458480a480f35b5080821015610c9f565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578173ffffffffffffffffffffffffffffffffffffffff610dc06122ed565b16918282526008602052610dd78183203390612a4f565b1561026457828252600660205280822033835260205281205533907ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645781610e536122ed565b913382526008602052610e8073ffffffffffffffffffffffffffffffffffffffff82842094168094612a4f565b15610264573382526006602052808220838352602052812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58380a380f35b50503461026457807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578091610efb6122ed565b610f03612315565b9073ffffffffffffffffffffffffffffffffffffffff809116835260066020528383209116825260205220548151906fffffffffffffffffffffffffffffffff8116825260801c6020820152f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264579060209173ffffffffffffffffffffffffffffffffffffffff610fa36122ed565b168252600a83528082205415159182610fc0575b50519015158152f35b819250600c84522054159038610fb7565b82843461045057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450575061100a6122ed565b6024359283611018336126d3565b1061102a57506020926104d291612c9a565b82517f10f6e63b000000000000000000000000000000000000000000000000000000008152fd5b83346104505760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505761109961108c6122ed565b611094612389565b612bb5565b80f35b8284346104505760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576110d56122ed565b9060243591604435916110e7836125b6565b9373ffffffffffffffffffffffffffffffffffffffff80931682526008602052858220915b848110611124578651806111208882612338565b0390f35b808461113460019385018661267f565b90549060031b1c166111468289612605565b520161110c565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645780519082600180549161118f836121c4565b8086529282811690811561121e57506001146111c2575b5050506111b882611120940383612217565b5191829182612287565b94508085527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b828610611206575050506111b882602061112095820101946111a6565b805460208787018101919091529095019481016111e9565b6111209750869350602092506111b89491507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001682840152151560051b820101946111a6565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff6112b66122ed565b1681526007845220549051908152f35b505034610264577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450576110996113006122ed565b61109461130b612315565b91611314612389565b612c4f565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102645760209073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754915191168152f35b50503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b057906113c76122ed565b908392839173ffffffffffffffffffffffffffffffffffffffff8094169384875260088252828720835190818482549182815201918a52848a20908a5b8181106114b4575050508161141a910382612217565b805191885b83811061145b5750505050600790848752528420557f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438380a380f35b9091929394955086895260068552858920826114778386612605565b51168a5285526fffffffffffffffffffffffffffffffff868a2054168089106114ab575b506001019291908795949361141f565b9750600161149b565b825484528a98509286019260019283019201611404565b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450578151918291600954808552602080950194600983527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af92905b82821061155657611120868661154c828b0383612217565b5191829182612338565b835487529586019560019384019390910190611534565b50503461026457602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05773ffffffffffffffffffffffffffffffffffffffff6115bd6122ed565b168352600882528083209281518093808654928381520195835280832092905b8282106115f557611120868661154c828b0383612217565b8354875295860195600193840193909101906115dd565b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff61165e6122ed565b1681526005845220549051908152f35b9050346106b0576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261183c576116a86122ed565b338552600a82528385205415801561182c575b6118045773ffffffffffffffffffffffffffffffffffffffff1691828552600882526116e933858720612864565b156117dd575081845260038152611702838520546128c0565b9282855260078252808520936fffffffffffffffffffffffffffffffff8554911694858092106117af575b50506002549182611765575b50505033907f60940192810a6fb3bce3fd3e2e3a13fd6ccc7605e963fb87ee971aba829989bd8480a480f35b7fffffffffffffffffffffffffffffffff000000000000000000000000000000009181600661179f935281882090338952528620926128c0565b60801b1683179055388080611739565b5583837f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438780a3833861172d565b83517faeccd4da000000000000000000000000000000000000000000000000000000008152fd5b8284517fcbb4b772000000000000000000000000000000000000000000000000000000008152fd5b50600c82528385205415156116bb565b8380fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261045057611872612389565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739278181547f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a35580f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff6119116122ed565b1681526003845220549051908152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090600b549051908152f35b919050346106b057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05781929135916024928335916119a3836125b6565b9481966009938454985b8681106119c1578751806111208b82612338565b8082018a811015611a1d579073ffffffffffffffffffffffffffffffffffffffff6001928888527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af015416611a16828c612605565b52016119ad565b84866032867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505763389a75e1600c52338152806020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c928280a280f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264578060209273ffffffffffffffffffffffffffffffffffffffff611afe6122ed565b1681526008845220549051908152f35b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450573381526020916008835280822090805193849281815496878152019581865282862090865b818110611c3257505050611b7d8486979695960386612217565b845194845b868110611bbf578580866007873384525281205580337f975923379ae9f0ac1f381324c85b0fea9f067891c4f674a9fe9db214ecfb0a438280a380f35b73ffffffffffffffffffffffffffffffffffffffff611bde8284612605565b511690611beb8285612a4f565b15610c09576001913388526006865286882081895286528787812055337ff655d5448541f499e8d15e12be905bce1d45ff3df14aeca2d174cc9eda1664e58980a301611b82565b825489529784019760019283019201611b63565b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b057611c7e6122ed565b906024359173ffffffffffffffffffffffffffffffffffffffff91827f00000000000000000000000012bce9dbffd8f20b1b7f74c9a5678f770fcb36b8163303611d135750827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092611cf68896600254612ba8565b60025516948585526003835280852082815401905551908152a380f35b84517f4d316367000000000000000000000000000000000000000000000000000000008152fd5b83346104505760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261045057611099611d756122ed565b611314612389565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090611db86123c1565b9051908152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020905160ff7f0000000000000000000000000000000000000000000000000000000000000012168152f35b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020906009549051908152f35b83807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505763389a75e1600c523381526202a30042016020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d8280a280f35b5050346102645760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261026457602090611db8611f006122ed565b6126d3565b8284346104505760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126104505750611f3f6122ed565b611f47612315565b906044359384611f56836126d3565b10611f695750926104d291602094612d12565b83517f10f6e63b000000000000000000000000000000000000000000000000000000008152fd5b82843461045057807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610450578151918291600b54808552602080950194600b83527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db992905b82821061201157611120868661154c828b0383612217565b835487529586019560019384019390910190611ff9565b50503461026457817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610264576020906002549051908152f35b9050346106b057817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b0576020926120a06122ed565b9183602435928392338252875273ffffffffffffffffffffffffffffffffffffffff8282209516948582528752205582519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925843392a35160018152f35b849084346106b057827ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126106b05782805461213d816121c4565b8085529160019180831690811561121e5750600114612168575050506111b882611120940383612217565b80809650527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8286106121ac575050506111b882602061112095820101946111a6565b8054602087870181019190915290950194810161218f565b90600182811c9216801561220d575b60208310146121de57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916121d3565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761225857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60208082528251818301819052939260005b8581106122d9575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201612299565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361231057565b600080fd5b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361231057565b6020908160408183019282815285518094520193019160005b82811061235f575050505090565b835173ffffffffffffffffffffffffffffffffffffffff1685529381019392810192600101612351565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433036123b357565b6382b429006000526004601cfd5b6000467f0000000000000000000000000000000000000000000000000000000000aa36a70361240f57507f7dc3770587816c954c8b0f7492179908aa339864c7c9ce4ab7df0e6ff304f37090565b6040518154829161241f826121c4565b8082528160209485820194600190878282169182600014612562575050600114612509575b5061245192500382612217565b51902091604051918201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f845260408301527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608301524660808301523060a083015260a0825260c082019082821067ffffffffffffffff8311176124dc575060405251902090565b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526041600452fd5b87805286915087907f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b85831061254a575050612451935082010138612444565b80548388018501528694508893909201918101612533565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016885261245195151560051b85010192503891506124449050565b67ffffffffffffffff81116122585760051b60200190565b906125c08261259e565b6125cd6040519182612217565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06125fb829461259e565b0190602036910137565b80518210156126195760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600b5481101561261957600b6000527f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90190600090565b80548210156126195760005260206000200190600090565b919082039182116126a457565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b73ffffffffffffffffffffffffffffffffffffffff16600052600360205261270b604060002054600760205260406000205490612697565b90565b6000818152600a60205260408120546127d857600954680100000000000000008110156127ab57600181018060095581101561277e5790826040927f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af0155600954928152600a6020522055600190565b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526032600452fd5b6024827f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905090565b6000818152600c60205260408120546127d857600b54680100000000000000008110156127ab57908261285061281b84600160409601600b55612648565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b9055600b54928152600c6020522055600190565b60008281526001820160205260409020546128b9578054906801000000000000000082101561225857826128a261281b84600180960185558461267f565b905580549260005201602052604060002055600190565b5050600090565b7001000000000000000000000000000000008110156128ee576fffffffffffffffffffffffffffffffff1690565b6335278d126000526004601cfd5b6000818152600c60205260408120549091908015612a4a577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90818101818111612a1d57600b54908382019182116129f0578082036129bc575b505050600b54801561298f5781019061296e82612648565b909182549160031b1b19169055600b558152600c6020526040812055600190565b6024847f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b6129da6129cb61281b93612648565b90549060031b1c928392612648565b90558452600c6020526040842055388080612956565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024857f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b505090565b90600182019060009281845282602052604084205490811515600014612ba1577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91828101818111612b7457825490848201918211612b4757808203612b12575b50505080548015612ae557820191612ac8838361267f565b909182549160031b1b191690555582526020526040812055600190565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526031600452fd5b612b32612b2261281b938661267f565b90549060031b1c9283928661267f565b90558652846020526040862055388080612ab0565b6024887f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b5050505090565b919082018092116126a457565b73ffffffffffffffffffffffffffffffffffffffff1680158015612c29575b612bff577f663bc5df9b13d61c4a5b97abcf8e3f327c80b0ee0c0db02c66536fe30399afab600080a2565b60046040517fcbb4b772000000000000000000000000000000000000000000000000000000008152fd5b50612c338161270e565b8015612c40575b15612bd4565b50612c4a816128fc565b612c3a565b73ffffffffffffffffffffffffffffffffffffffff16612c6e816127dd565b15612bff577fd8447e2a6ccc1f3caeea39fdaea6ca5c1c22a9ab79022d1e39a8c24f0736e549600080a2565b73ffffffffffffffffffffffffffffffffffffffff903360005260036020526040600020612cc9848254612697565b9055169081600052600360205260406000208181540190556040519081527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203392a3600190565b919073ffffffffffffffffffffffffffffffffffffffff80931691338314612df457907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91600094848652602092600484526040918291828920338a52865282892054857fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612dd1575b505087895260038652828920612db5868254612697565b90551696878152600385522082815401905551908152a3600190565b612dda91612697565b888a5260048752838a20338b528752838a20553885612d9e565b915061270b9250612c9a56fea164736f6c6343000813000a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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