ETH Price: $2,109.33 (+1.48%)

Transaction Decoder

Block:
19322050 at Feb-27-2024 11:05:35 PM +UTC
Transaction Fee:
0.00273778251793527 ETH $5.77
Gas Used:
59,865 Gas / 45.732606998 Gwei

Emitted Events:

310 0xf12a38e6e51913ea04d70dba97d7420a13fd7941.0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d( 0x2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d, 0x9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6, 0x000000000000000000000000ecabf4d8fdbb45eabed0daf25fd690eaaa4d9a9e, 0x000000000000000000000000269e944ad9140fc6e21794e8ea71ce1afbfe38c8 )

Execution Trace

0xf12a38e6e51913ea04d70dba97d7420a13fd7941.2f2ff15d( )
  • UpgradeableBeacon.STATICCALL( )
  • DShare.grantRole( role=9F2DF0FED2C77648DE5860A4CC508CD0818C85B8B8A1AB4CEEEF8D981C8956A6, account=0xeCabf4d8FDBb45eaBEd0Daf25FD690EAaA4D9a9E )
    File 1 of 2: UpgradeableBeacon
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol)
    pragma solidity ^0.8.20;
    import {IBeacon} from "./IBeacon.sol";
    import {Ownable} from "../../access/Ownable.sol";
    /**
     * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
     * implementation contract, which is where they will delegate all function calls.
     *
     * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
     */
    contract UpgradeableBeacon is IBeacon, Ownable {
        address private _implementation;
        /**
         * @dev The `implementation` of the beacon is invalid.
         */
        error BeaconInvalidImplementation(address implementation);
        /**
         * @dev Emitted when the implementation returned by the beacon is changed.
         */
        event Upgraded(address indexed implementation);
        /**
         * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon.
         */
        constructor(address implementation_, address initialOwner) Ownable(initialOwner) {
            _setImplementation(implementation_);
        }
        /**
         * @dev Returns the current implementation address.
         */
        function implementation() public view virtual returns (address) {
            return _implementation;
        }
        /**
         * @dev Upgrades the beacon to a new implementation.
         *
         * Emits an {Upgraded} event.
         *
         * Requirements:
         *
         * - msg.sender must be the owner of the contract.
         * - `newImplementation` must be a contract.
         */
        function upgradeTo(address newImplementation) public virtual onlyOwner {
            _setImplementation(newImplementation);
        }
        /**
         * @dev Sets the implementation contract address for this beacon
         *
         * Requirements:
         *
         * - `newImplementation` must be a contract.
         */
        function _setImplementation(address newImplementation) private {
            if (newImplementation.code.length == 0) {
                revert BeaconInvalidImplementation(newImplementation);
            }
            _implementation = newImplementation;
            emit Upgraded(newImplementation);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev This is the interface that {BeaconProxy} expects of its beacon.
     */
    interface IBeacon {
        /**
         * @dev Must return an address that can be used as a delegate call target.
         *
         * {UpgradeableBeacon} will check that this address is a contract.
         */
        function implementation() external view returns (address);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
    pragma solidity ^0.8.20;
    import {Context} from "../utils/Context.sol";
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * The initial owner is set to the address provided by the deployer. This can
     * later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
        /**
         * @dev The caller account is not authorized to perform an operation.
         */
        error OwnableUnauthorizedAccount(address account);
        /**
         * @dev The owner is not a valid owner account. (eg. `address(0)`)
         */
        error OwnableInvalidOwner(address owner);
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
         */
        constructor(address initialOwner) {
            if (initialOwner == address(0)) {
                revert OwnableInvalidOwner(address(0));
            }
            _transferOwnership(initialOwner);
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            if (owner() != _msgSender()) {
                revert OwnableUnauthorizedAccount(_msgSender());
            }
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby disabling any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(address(0));
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            if (newOwner == address(0)) {
                revert OwnableInvalidOwner(address(0));
            }
            _transferOwnership(newOwner);
        }
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    

    File 2 of 2: DShare
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.22;
    import {Initializable} from "openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol";
    import {AccessControlDefaultAdminRulesUpgradeable} from
        "openzeppelin-contracts-upgradeable/contracts/access/extensions/AccessControlDefaultAdminRulesUpgradeable.sol";
    import {IDShare, ITransferRestrictor} from "./IDShare.sol";
    import {ERC20Rebasing} from "./ERC20Rebasing.sol";
    /// @notice Core token contract for bridged assets. Rebases on stock splits.
    /// ERC20 with minter, burner, and blacklist
    /// Uses solady ERC20 which allows EIP-2612 domain separator with `name` changes
    /// @author Dinari (https://github.com/dinaricrypto/sbt-contracts/blob/main/src/dShare.sol)
    contract DShare is IDShare, Initializable, ERC20Rebasing, AccessControlDefaultAdminRulesUpgradeable {
        /// ------------------ Types ------------------ ///
        error Unauthorized();
        error ZeroValue();
        /// @dev Emitted when `name` is set
        event NameSet(string name);
        /// @dev Emitted when `symbol` is set
        event SymbolSet(string symbol);
        /// @dev Emitted when transfer restrictor contract is set
        event TransferRestrictorSet(ITransferRestrictor indexed transferRestrictor);
        /// @dev Emitted when split factor is updated
        event BalancePerShareSet(uint256 balancePerShare);
        /// ------------------ Immutables ------------------ ///
        /// @notice Role for approved minters
        bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
        /// @notice Role for approved burners
        bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
        /// ------------------ State ------------------ ///
        struct dShareStorage {
            string _name;
            string _symbol;
            ITransferRestrictor _transferRestrictor;
            /// @dev Aggregate mult factor due to splits since deployment, ethers decimals
            uint128 _balancePerShare;
        }
        // keccak256(abi.encode(uint256(keccak256("dinaricrypto.storage.DShare")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant dShareStorageLocation = 0x7315beb2381679795e06870021c0fca5deb85616e29e098c2e7b7e488f185800;
        function _getdShareStorage() private pure returns (dShareStorage storage $) {
            assembly {
                $.slot := dShareStorageLocation
            }
        }
        /// ------------------ Initialization ------------------ ///
        function initialize(
            address owner,
            string memory _name,
            string memory _symbol,
            ITransferRestrictor _transferRestrictor
        ) public initializer {
            __AccessControlDefaultAdminRules_init_unchained(0, owner);
            dShareStorage storage $ = _getdShareStorage();
            $._name = _name;
            $._symbol = _symbol;
            $._transferRestrictor = _transferRestrictor;
            $._balancePerShare = _INITIAL_BALANCE_PER_SHARE;
        }
        /// @custom:oz-upgrades-unsafe-allow constructor
        constructor() {
            _disableInitializers();
        }
        /// ------------------ Getters ------------------ ///
        /// @notice Token name
        function name() public view override returns (string memory) {
            dShareStorage storage $ = _getdShareStorage();
            return $._name;
        }
        /// @notice Token symbol
        function symbol() public view override returns (string memory) {
            dShareStorage storage $ = _getdShareStorage();
            return $._symbol;
        }
        /// @notice Contract to restrict transfers
        function transferRestrictor() public view returns (ITransferRestrictor) {
            dShareStorage storage $ = _getdShareStorage();
            return $._transferRestrictor;
        }
        function balancePerShare() public view override returns (uint128) {
            dShareStorage storage $ = _getdShareStorage();
            uint128 _balancePerShare = $._balancePerShare;
            // Override with default if not set due to upgrade
            if (_balancePerShare == 0) return _INITIAL_BALANCE_PER_SHARE;
            return _balancePerShare;
        }
        /// ------------------ Setters ------------------ ///
        /// @notice Set token name
        /// @dev Only callable by owner or deployer
        function setName(string calldata newName) external onlyRole(DEFAULT_ADMIN_ROLE) {
            dShareStorage storage $ = _getdShareStorage();
            $._name = newName;
            emit NameSet(newName);
        }
        /// @notice Set token symbol
        /// @dev Only callable by owner or deployer
        function setSymbol(string calldata newSymbol) external onlyRole(DEFAULT_ADMIN_ROLE) {
            dShareStorage storage $ = _getdShareStorage();
            $._symbol = newSymbol;
            emit SymbolSet(newSymbol);
        }
        /// @notice Update split factor
        /// @dev Relies on offchain computation of aggregate splits and reverse splits
        function setBalancePerShare(uint128 balancePerShare_) external onlyRole(DEFAULT_ADMIN_ROLE) {
            if (balancePerShare_ == 0) revert ZeroValue();
            dShareStorage storage $ = _getdShareStorage();
            $._balancePerShare = balancePerShare_;
            emit BalancePerShareSet(balancePerShare_);
        }
        /// @notice Set transfer restrictor contract
        /// @dev Only callable by owner
        function setTransferRestrictor(ITransferRestrictor newRestrictor) external onlyRole(DEFAULT_ADMIN_ROLE) {
            dShareStorage storage $ = _getdShareStorage();
            $._transferRestrictor = newRestrictor;
            emit TransferRestrictorSet(newRestrictor);
        }
        /// ------------------ Minting and Burning ------------------ ///
        /// @notice Mint tokens
        /// @param to Address to mint tokens to
        /// @param value Amount of tokens to mint
        /// @dev Only callable by approved minter
        function mint(address to, uint256 value) external onlyRole(MINTER_ROLE) {
            _mint(to, value);
        }
        /// @notice Burn tokens
        /// @param value Amount of tokens to burn
        /// @dev Only callable by approved burner
        function burn(uint256 value) external onlyRole(BURNER_ROLE) {
            _burn(msg.sender, value);
        }
        /// @notice Burn tokens from an account
        /// @param account Address to burn tokens from
        /// @param value Amount of tokens to burn
        /// @dev Only callable by approved burner
        function burnFrom(address account, uint256 value) external onlyRole(BURNER_ROLE) {
            _spendAllowance(account, msg.sender, value);
            _burn(account, value);
        }
        /// ------------------ Transfers ------------------ ///
        function _beforeTokenTransfer(address from, address to, uint256) internal view override {
            // If transferRestrictor is not set, no restrictions are applied
            dShareStorage storage $ = _getdShareStorage();
            ITransferRestrictor _transferRestrictor = $._transferRestrictor;
            if (address(_transferRestrictor) != address(0)) {
                // Check transfer restrictions
                _transferRestrictor.requireNotRestricted(from, to);
            }
        }
        /**
         * @param account The address of the account
         * @return Whether the account is blacklisted
         * @dev Returns true if the account is blacklisted , if the account is the zero address
         */
        function isBlacklisted(address account) external view returns (bool) {
            dShareStorage storage $ = _getdShareStorage();
            ITransferRestrictor _transferRestrictor = $._transferRestrictor;
            if (address(_transferRestrictor) == address(0)) return false;
            return _transferRestrictor.isBlacklisted(account);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
     * case an upgrade adds a module that needs to be initialized.
     *
     * For example:
     *
     * [.hljs-theme-light.nopadding]
     * ```solidity
     * contract MyToken is ERC20Upgradeable {
     *     function initialize() initializer public {
     *         __ERC20_init("MyToken", "MTK");
     *     }
     * }
     *
     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
     *     function initializeV2() reinitializer(2) public {
     *         __ERC20Permit_init("MyToken");
     *     }
     * }
     * ```
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     *
     * [CAUTION]
     * ====
     * Avoid leaving a contract uninitialized.
     *
     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * /// @custom:oz-upgrades-unsafe-allow constructor
     * constructor() {
     *     _disableInitializers();
     * }
     * ```
     * ====
     */
    abstract contract Initializable {
        /**
         * @dev Storage of the initializable contract.
         *
         * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
         * when using with upgradeable contracts.
         *
         * @custom:storage-location erc7201:openzeppelin.storage.Initializable
         */
        struct InitializableStorage {
            /**
             * @dev Indicates that the contract has been initialized.
             */
            uint64 _initialized;
            /**
             * @dev Indicates that the contract is in the process of being initialized.
             */
            bool _initializing;
        }
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
        /**
         * @dev The contract is already initialized.
         */
        error InvalidInitialization();
        /**
         * @dev The contract is not initializing.
         */
        error NotInitializing();
        /**
         * @dev Triggered when the contract has been initialized or reinitialized.
         */
        event Initialized(uint64 version);
        /**
         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
         * `onlyInitializing` functions can be used to initialize parent contracts.
         *
         * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
         * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
         * production.
         *
         * Emits an {Initialized} event.
         */
        modifier initializer() {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
            // Cache values to avoid duplicated sloads
            bool isTopLevelCall = !$._initializing;
            uint64 initialized = $._initialized;
            // Allowed calls:
            // - initialSetup: the contract is not in the initializing state and no previous version was
            //                 initialized
            // - construction: the contract is initialized at version 1 (no reininitialization) and the
            //                 current contract is just being deployed
            bool initialSetup = initialized == 0 && isTopLevelCall;
            bool construction = initialized == 1 && address(this).code.length == 0;
            if (!initialSetup && !construction) {
                revert InvalidInitialization();
            }
            $._initialized = 1;
            if (isTopLevelCall) {
                $._initializing = true;
            }
            _;
            if (isTopLevelCall) {
                $._initializing = false;
                emit Initialized(1);
            }
        }
        /**
         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
         * used to initialize parent contracts.
         *
         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
         * are added through upgrades and that require initialization.
         *
         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
         * cannot be nested. If one is invoked in the context of another, execution will revert.
         *
         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
         * a contract, executing them in the right order is up to the developer or operator.
         *
         * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
         *
         * Emits an {Initialized} event.
         */
        modifier reinitializer(uint64 version) {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
            if ($._initializing || $._initialized >= version) {
                revert InvalidInitialization();
            }
            $._initialized = version;
            $._initializing = true;
            _;
            $._initializing = false;
            emit Initialized(version);
        }
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} and {reinitializer} modifiers, directly or indirectly.
         */
        modifier onlyInitializing() {
            _checkInitializing();
            _;
        }
        /**
         * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
         */
        function _checkInitializing() internal view virtual {
            if (!_isInitializing()) {
                revert NotInitializing();
            }
        }
        /**
         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
         * through proxies.
         *
         * Emits an {Initialized} event the first time it is successfully executed.
         */
        function _disableInitializers() internal virtual {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
            if ($._initializing) {
                revert InvalidInitialization();
            }
            if ($._initialized != type(uint64).max) {
                $._initialized = type(uint64).max;
                emit Initialized(type(uint64).max);
            }
        }
        /**
         * @dev Returns the highest version that has been initialized. See {reinitializer}.
         */
        function _getInitializedVersion() internal view returns (uint64) {
            return _getInitializableStorage()._initialized;
        }
        /**
         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
         */
        function _isInitializing() internal view returns (bool) {
            return _getInitializableStorage()._initializing;
        }
        /**
         * @dev Returns a pointer to the storage namespace.
         */
        // solhint-disable-next-line var-name-mixedcase
        function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
            assembly {
                $.slot := INITIALIZABLE_STORAGE
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlDefaultAdminRules.sol)
    pragma solidity ^0.8.20;
    import {IAccessControlDefaultAdminRules} from "@openzeppelin/contracts/access/extensions/IAccessControlDefaultAdminRules.sol";
    import {AccessControlUpgradeable} from "../AccessControlUpgradeable.sol";
    import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
    import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
    import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
    import {IERC5313} from "@openzeppelin/contracts/interfaces/IERC5313.sol";
    import {Initializable} from "../../proxy/utils/Initializable.sol";
    /**
     * @dev Extension of {AccessControl} that allows specifying special rules to manage
     * the `DEFAULT_ADMIN_ROLE` holder, which is a sensitive role with special permissions
     * over other roles that may potentially have privileged rights in the system.
     *
     * If a specific role doesn't have an admin role assigned, the holder of the
     * `DEFAULT_ADMIN_ROLE` will have the ability to grant it and revoke it.
     *
     * This contract implements the following risk mitigations on top of {AccessControl}:
     *
     * * Only one account holds the `DEFAULT_ADMIN_ROLE` since deployment until it's potentially renounced.
     * * Enforces a 2-step process to transfer the `DEFAULT_ADMIN_ROLE` to another account.
     * * Enforces a configurable delay between the two steps, with the ability to cancel before the transfer is accepted.
     * * The delay can be changed by scheduling, see {changeDefaultAdminDelay}.
     * * It is not possible to use another role to manage the `DEFAULT_ADMIN_ROLE`.
     *
     * Example usage:
     *
     * ```solidity
     * contract MyToken is AccessControlDefaultAdminRules {
     *   constructor() AccessControlDefaultAdminRules(
     *     3 days,
     *     msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder
     *    ) {}
     * }
     * ```
     */
    abstract contract AccessControlDefaultAdminRulesUpgradeable is Initializable, IAccessControlDefaultAdminRules, IERC5313, AccessControlUpgradeable {
        /// @custom:storage-location erc7201:openzeppelin.storage.AccessControlDefaultAdminRules
        struct AccessControlDefaultAdminRulesStorage {
            // pending admin pair read/written together frequently
            address _pendingDefaultAdmin;
            uint48 _pendingDefaultAdminSchedule; // 0 == unset
            uint48 _currentDelay;
            address _currentDefaultAdmin;
            // pending delay pair read/written together frequently
            uint48 _pendingDelay;
            uint48 _pendingDelaySchedule; // 0 == unset
        }
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControlDefaultAdminRules")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant AccessControlDefaultAdminRulesStorageLocation = 0xeef3dac4538c82c8ace4063ab0acd2d15cdb5883aa1dff7c2673abb3d8698400;
        function _getAccessControlDefaultAdminRulesStorage() private pure returns (AccessControlDefaultAdminRulesStorage storage $) {
            assembly {
                $.slot := AccessControlDefaultAdminRulesStorageLocation
            }
        }
        /**
         * @dev Sets the initial values for {defaultAdminDelay} and {defaultAdmin} address.
         */
        function __AccessControlDefaultAdminRules_init(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {
            __AccessControlDefaultAdminRules_init_unchained(initialDelay, initialDefaultAdmin);
        }
        function __AccessControlDefaultAdminRules_init_unchained(uint48 initialDelay, address initialDefaultAdmin) internal onlyInitializing {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            if (initialDefaultAdmin == address(0)) {
                revert AccessControlInvalidDefaultAdmin(address(0));
            }
            $._currentDelay = initialDelay;
            _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin);
        }
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId);
        }
        /**
         * @dev See {IERC5313-owner}.
         */
        function owner() public view virtual returns (address) {
            return defaultAdmin();
        }
        ///
        /// Override AccessControl role management
        ///
        /**
         * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
         */
        function grantRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {
            if (role == DEFAULT_ADMIN_ROLE) {
                revert AccessControlEnforcedDefaultAdminRules();
            }
            super.grantRole(role, account);
        }
        /**
         * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`.
         */
        function revokeRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {
            if (role == DEFAULT_ADMIN_ROLE) {
                revert AccessControlEnforcedDefaultAdminRules();
            }
            super.revokeRole(role, account);
        }
        /**
         * @dev See {AccessControl-renounceRole}.
         *
         * For the `DEFAULT_ADMIN_ROLE`, it only allows renouncing in two steps by first calling
         * {beginDefaultAdminTransfer} to the `address(0)`, so it's required that the {pendingDefaultAdmin} schedule
         * has also passed when calling this function.
         *
         * After its execution, it will not be possible to call `onlyRole(DEFAULT_ADMIN_ROLE)` functions.
         *
         * NOTE: Renouncing `DEFAULT_ADMIN_ROLE` will leave the contract without a {defaultAdmin},
         * thereby disabling any functionality that is only available for it, and the possibility of reassigning a
         * non-administrated role.
         */
        function renounceRole(bytes32 role, address account) public virtual override(AccessControlUpgradeable, IAccessControl) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
                (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin();
                if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
                    revert AccessControlEnforcedDefaultAdminDelay(schedule);
                }
                delete $._pendingDefaultAdminSchedule;
            }
            super.renounceRole(role, account);
        }
        /**
         * @dev See {AccessControl-_grantRole}.
         *
         * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the
         * role has been previously renounced.
         *
         * NOTE: Exposing this function through another mechanism may make the `DEFAULT_ADMIN_ROLE`
         * assignable again. Make sure to guarantee this is the expected behavior in your implementation.
         */
        function _grantRole(bytes32 role, address account) internal virtual override returns (bool) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            if (role == DEFAULT_ADMIN_ROLE) {
                if (defaultAdmin() != address(0)) {
                    revert AccessControlEnforcedDefaultAdminRules();
                }
                $._currentDefaultAdmin = account;
            }
            return super._grantRole(role, account);
        }
        /**
         * @dev See {AccessControl-_revokeRole}.
         */
        function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) {
                delete $._currentDefaultAdmin;
            }
            return super._revokeRole(role, account);
        }
        /**
         * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`.
         */
        function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override {
            if (role == DEFAULT_ADMIN_ROLE) {
                revert AccessControlEnforcedDefaultAdminRules();
            }
            super._setRoleAdmin(role, adminRole);
        }
        ///
        /// AccessControlDefaultAdminRules accessors
        ///
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function defaultAdmin() public view virtual returns (address) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            return $._currentDefaultAdmin;
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function pendingDefaultAdmin() public view virtual returns (address newAdmin, uint48 schedule) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            return ($._pendingDefaultAdmin, $._pendingDefaultAdminSchedule);
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function defaultAdminDelay() public view virtual returns (uint48) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            uint48 schedule = $._pendingDelaySchedule;
            return (_isScheduleSet(schedule) && _hasSchedulePassed(schedule)) ? $._pendingDelay : $._currentDelay;
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function pendingDefaultAdminDelay() public view virtual returns (uint48 newDelay, uint48 schedule) {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            schedule = $._pendingDelaySchedule;
            return (_isScheduleSet(schedule) && !_hasSchedulePassed(schedule)) ? ($._pendingDelay, schedule) : (0, 0);
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function defaultAdminDelayIncreaseWait() public view virtual returns (uint48) {
            return 5 days;
        }
        ///
        /// AccessControlDefaultAdminRules public and internal setters for defaultAdmin/pendingDefaultAdmin
        ///
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function beginDefaultAdminTransfer(address newAdmin) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
            _beginDefaultAdminTransfer(newAdmin);
        }
        /**
         * @dev See {beginDefaultAdminTransfer}.
         *
         * Internal function without access restriction.
         */
        function _beginDefaultAdminTransfer(address newAdmin) internal virtual {
            uint48 newSchedule = SafeCast.toUint48(block.timestamp) + defaultAdminDelay();
            _setPendingDefaultAdmin(newAdmin, newSchedule);
            emit DefaultAdminTransferScheduled(newAdmin, newSchedule);
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function cancelDefaultAdminTransfer() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
            _cancelDefaultAdminTransfer();
        }
        /**
         * @dev See {cancelDefaultAdminTransfer}.
         *
         * Internal function without access restriction.
         */
        function _cancelDefaultAdminTransfer() internal virtual {
            _setPendingDefaultAdmin(address(0), 0);
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function acceptDefaultAdminTransfer() public virtual {
            (address newDefaultAdmin, ) = pendingDefaultAdmin();
            if (_msgSender() != newDefaultAdmin) {
                // Enforce newDefaultAdmin explicit acceptance.
                revert AccessControlInvalidDefaultAdmin(_msgSender());
            }
            _acceptDefaultAdminTransfer();
        }
        /**
         * @dev See {acceptDefaultAdminTransfer}.
         *
         * Internal function without access restriction.
         */
        function _acceptDefaultAdminTransfer() internal virtual {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            (address newAdmin, uint48 schedule) = pendingDefaultAdmin();
            if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) {
                revert AccessControlEnforcedDefaultAdminDelay(schedule);
            }
            _revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin());
            _grantRole(DEFAULT_ADMIN_ROLE, newAdmin);
            delete $._pendingDefaultAdmin;
            delete $._pendingDefaultAdminSchedule;
        }
        ///
        /// AccessControlDefaultAdminRules public and internal setters for defaultAdminDelay/pendingDefaultAdminDelay
        ///
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function changeDefaultAdminDelay(uint48 newDelay) public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
            _changeDefaultAdminDelay(newDelay);
        }
        /**
         * @dev See {changeDefaultAdminDelay}.
         *
         * Internal function without access restriction.
         */
        function _changeDefaultAdminDelay(uint48 newDelay) internal virtual {
            uint48 newSchedule = SafeCast.toUint48(block.timestamp) + _delayChangeWait(newDelay);
            _setPendingDelay(newDelay, newSchedule);
            emit DefaultAdminDelayChangeScheduled(newDelay, newSchedule);
        }
        /**
         * @inheritdoc IAccessControlDefaultAdminRules
         */
        function rollbackDefaultAdminDelay() public virtual onlyRole(DEFAULT_ADMIN_ROLE) {
            _rollbackDefaultAdminDelay();
        }
        /**
         * @dev See {rollbackDefaultAdminDelay}.
         *
         * Internal function without access restriction.
         */
        function _rollbackDefaultAdminDelay() internal virtual {
            _setPendingDelay(0, 0);
        }
        /**
         * @dev Returns the amount of seconds to wait after the `newDelay` will
         * become the new {defaultAdminDelay}.
         *
         * The value returned guarantees that if the delay is reduced, it will go into effect
         * after a wait that honors the previously set delay.
         *
         * See {defaultAdminDelayIncreaseWait}.
         */
        function _delayChangeWait(uint48 newDelay) internal view virtual returns (uint48) {
            uint48 currentDelay = defaultAdminDelay();
            // When increasing the delay, we schedule the delay change to occur after a period of "new delay" has passed, up
            // to a maximum given by defaultAdminDelayIncreaseWait, by default 5 days. For example, if increasing from 1 day
            // to 3 days, the new delay will come into effect after 3 days. If increasing from 1 day to 10 days, the new
            // delay will come into effect after 5 days. The 5 day wait period is intended to be able to fix an error like
            // using milliseconds instead of seconds.
            //
            // When decreasing the delay, we wait the difference between "current delay" and "new delay". This guarantees
            // that an admin transfer cannot be made faster than "current delay" at the time the delay change is scheduled.
            // For example, if decreasing from 10 days to 3 days, the new delay will come into effect after 7 days.
            return
                newDelay > currentDelay
                    ? uint48(Math.min(newDelay, defaultAdminDelayIncreaseWait())) // no need to safecast, both inputs are uint48
                    : currentDelay - newDelay;
        }
        ///
        /// Private setters
        ///
        /**
         * @dev Setter of the tuple for pending admin and its schedule.
         *
         * May emit a DefaultAdminTransferCanceled event.
         */
        function _setPendingDefaultAdmin(address newAdmin, uint48 newSchedule) private {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            (, uint48 oldSchedule) = pendingDefaultAdmin();
            $._pendingDefaultAdmin = newAdmin;
            $._pendingDefaultAdminSchedule = newSchedule;
            // An `oldSchedule` from `pendingDefaultAdmin()` is only set if it hasn't been accepted.
            if (_isScheduleSet(oldSchedule)) {
                // Emit for implicit cancellations when another default admin was scheduled.
                emit DefaultAdminTransferCanceled();
            }
        }
        /**
         * @dev Setter of the tuple for pending delay and its schedule.
         *
         * May emit a DefaultAdminDelayChangeCanceled event.
         */
        function _setPendingDelay(uint48 newDelay, uint48 newSchedule) private {
            AccessControlDefaultAdminRulesStorage storage $ = _getAccessControlDefaultAdminRulesStorage();
            uint48 oldSchedule = $._pendingDelaySchedule;
            if (_isScheduleSet(oldSchedule)) {
                if (_hasSchedulePassed(oldSchedule)) {
                    // Materialize a virtual delay
                    $._currentDelay = $._pendingDelay;
                } else {
                    // Emit for implicit cancellations when another delay was scheduled.
                    emit DefaultAdminDelayChangeCanceled();
                }
            }
            $._pendingDelay = newDelay;
            $._pendingDelaySchedule = newSchedule;
        }
        ///
        /// Private helpers
        ///
        /**
         * @dev Defines if an `schedule` is considered set. For consistency purposes.
         */
        function _isScheduleSet(uint48 schedule) private pure returns (bool) {
            return schedule != 0;
        }
        /**
         * @dev Defines if an `schedule` is considered passed. For consistency purposes.
         */
        function _hasSchedulePassed(uint48 schedule) private view returns (bool) {
            return schedule < block.timestamp;
        }
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.22;
    import {ITransferRestrictor} from "./ITransferRestrictor.sol";
    /// @notice Core token contract interface for bridged assets.
    /// @author Dinari (https://github.com/dinaricrypto/sbt-contracts/blob/main/src/IDShare.sol)
    /// Minter, burner, and blacklist
    interface IDShare {
        /// @notice Contract to restrict transfers
        function transferRestrictor() external view returns (ITransferRestrictor);
        /// @notice Mint tokens
        /// @param to Address to mint tokens to
        /// @param value Amount of tokens to mint
        /// @dev Only callable by approved minter and deployer
        /// @dev Not callable after split
        function mint(address to, uint256 value) external;
        /// @notice Burn tokens
        /// @param value Amount of tokens to burn
        /// @dev Only callable by approved burner
        /// @dev Deployer can always burn after split
        function burn(uint256 value) external;
        /**
         * @param account The address of the account
         * @return Whether the account is blacklisted
         * @dev Returns true if the account is blacklisted , if the account is the zero address
         */
        function isBlacklisted(address account) external view returns (bool);
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.22;
    import {ERC20} from "solady/src/tokens/ERC20.sol";
    import {mulDiv, mulDiv18} from "prb-math/Common.sol";
    import {NumberUtils} from "./common/NumberUtils.sol";
    /// @notice Rebasing ERC20 token as an in-place upgrade to solady erc20
    /// @author Dinari (https://github.com/dinaricrypto/sbt-contracts/blob/main/src/dShare.sol)
    abstract contract ERC20Rebasing is ERC20 {
        uint256 private constant _TRANSFER_EVENT_SIGNATURE =
            0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
        uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
        uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
        uint128 internal constant _INITIAL_BALANCE_PER_SHARE = 1 ether;
        /**
         * @dev Returns the number of tokens an internal share amount represents.
         * This amount is assumed to have 18 decimals and is divided by 10 **18 when applied.
         */
        function balancePerShare() public view virtual returns (uint128);
        function sharesToBalance(uint256 shares) public view returns (uint256) {
            return mulDiv18(shares, balancePerShare()); // floor
        }
        function balanceToShares(uint256 balance) public view returns (uint256) {
            return mulDiv(balance, _INITIAL_BALANCE_PER_SHARE, balancePerShare()); // floor
        }
        /// ------------------ ERC20 ------------------
        function totalSupply() public view virtual override returns (uint256) {
            return sharesToBalance(super.totalSupply());
        }
        function maxSupply() public view virtual returns (uint256) {
            uint128 balancePerShare_ = balancePerShare();
            if (balancePerShare_ < _INITIAL_BALANCE_PER_SHARE) {
                return mulDiv18(type(uint256).max, balancePerShare_);
            } else if (balancePerShare_ > _INITIAL_BALANCE_PER_SHARE) {
                return mulDiv(type(uint256).max, _INITIAL_BALANCE_PER_SHARE, balancePerShare_);
            }
            return type(uint256).max;
        }
        function balanceOf(address account) public view virtual override returns (uint256) {
            return sharesToBalance(super.balanceOf(account));
        }
        function sharesOf(address account) public view virtual returns (uint256) {
            return super.balanceOf(account);
        }
        function transfer(address to, uint256 amount) public virtual override returns (bool) {
            _transfer(msg.sender, to, amount);
            return true;
        }
        function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
            _spendAllowance(from, msg.sender, amount);
            _transfer(from, to, amount);
            return true;
        }
        // Convert to shares
        function _transfer(address from, address to, uint256 amount) internal virtual override {
            _beforeTokenTransfer(from, to, amount);
            uint256 shares = balanceToShares(amount);
            /// @solidity memory-safe-assembly
            assembly {
                let from_ := shl(96, from)
                // Compute the balance slot and load its value.
                mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
                let fromBalanceSlot := keccak256(0x0c, 0x20)
                let fromBalance := sload(fromBalanceSlot)
                // Revert if insufficient balance.
                if gt(shares, fromBalance) {
                    mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated balance.
                sstore(fromBalanceSlot, sub(fromBalance, shares))
                // Compute the balance slot of `to`.
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x20)
                // Add and store the updated balance of `to`.
                // Will not overflow because the sum of all user balances
                // cannot exceed the maximum uint256 value.
                sstore(toBalanceSlot, add(sload(toBalanceSlot), shares))
                // Emit the {Transfer} event.
                mstore(0x20, amount)
                log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
            }
            _afterTokenTransfer(from, to, amount);
        }
        // Convert to shares
        function _mint(address to, uint256 amount) internal virtual override {
            _beforeTokenTransfer(address(0), to, amount);
            uint256 totalSharesBefore = super.totalSupply();
            uint256 totalSupplyBefore = sharesToBalance(totalSharesBefore);
            uint256 totalSupplyAfter = 0;
            unchecked {
                totalSupplyAfter = totalSupplyBefore + amount;
                if (totalSupplyAfter < totalSupplyBefore) revert TotalSupplyOverflow();
            }
            if (NumberUtils.mulDivCheckOverflow(totalSupplyAfter, _INITIAL_BALANCE_PER_SHARE, balancePerShare())) {
                revert TotalSupplyOverflow();
            }
            uint256 shares = balanceToShares(amount);
            uint256 totalSharesAfter = 0;
            unchecked {
                totalSharesAfter = totalSharesBefore + shares;
            }
            /// @solidity memory-safe-assembly
            assembly {
                // Store the updated total supply.
                sstore(_TOTAL_SUPPLY_SLOT, totalSharesAfter)
                // Compute the balance slot and load its value.
                mstore(0x0c, _BALANCE_SLOT_SEED)
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x20)
                // Add and store the updated balance.
                sstore(toBalanceSlot, add(sload(toBalanceSlot), shares))
                // Emit the {Transfer} event.
                mstore(0x20, amount)
                log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
            }
            _afterTokenTransfer(address(0), to, amount);
        }
        // Convert to shares
        function _burn(address from, uint256 amount) internal virtual override {
            _beforeTokenTransfer(from, address(0), amount);
            uint256 shares = balanceToShares(amount);
            /// @solidity memory-safe-assembly
            assembly {
                // Compute the balance slot and load its value.
                mstore(0x0c, _BALANCE_SLOT_SEED)
                mstore(0x00, from)
                let fromBalanceSlot := keccak256(0x0c, 0x20)
                let fromBalance := sload(fromBalanceSlot)
                // Revert if insufficient balance.
                if gt(shares, fromBalance) {
                    mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated balance.
                sstore(fromBalanceSlot, sub(fromBalance, shares))
                // Subtract and store the updated total supply.
                sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), shares))
                // Emit the {Transfer} event.
                mstore(0x00, amount)
                log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
            }
            _afterTokenTransfer(from, address(0), amount);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlDefaultAdminRules.sol)
    pragma solidity ^0.8.20;
    import {IAccessControl} from "../IAccessControl.sol";
    /**
     * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection.
     */
    interface IAccessControlDefaultAdminRules is IAccessControl {
        /**
         * @dev The new default admin is not a valid default admin.
         */
        error AccessControlInvalidDefaultAdmin(address defaultAdmin);
        /**
         * @dev At least one of the following rules was violated:
         *
         * - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.
         * - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.
         * - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.
         */
        error AccessControlEnforcedDefaultAdminRules();
        /**
         * @dev The delay for transferring the default admin delay is enforced and
         * the operation must wait until `schedule`.
         *
         * NOTE: `schedule` can be 0 indicating there's no transfer scheduled.
         */
        error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);
        /**
         * @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next
         * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`
         * passes.
         */
        event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);
        /**
         * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule.
         */
        event DefaultAdminTransferCanceled();
        /**
         * @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next
         * delay to be applied between default admin transfer after `effectSchedule` has passed.
         */
        event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);
        /**
         * @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass.
         */
        event DefaultAdminDelayChangeCanceled();
        /**
         * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder.
         */
        function defaultAdmin() external view returns (address);
        /**
         * @dev Returns a tuple of a `newAdmin` and an accept schedule.
         *
         * After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role
         * by calling {acceptDefaultAdminTransfer}, completing the role transfer.
         *
         * A zero value only in `acceptSchedule` indicates no pending admin transfer.
         *
         * NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced.
         */
        function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule);
        /**
         * @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started.
         *
         * This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set
         * the acceptance schedule.
         *
         * NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this
         * function returns the new delay. See {changeDefaultAdminDelay}.
         */
        function defaultAdminDelay() external view returns (uint48);
        /**
         * @dev Returns a tuple of `newDelay` and an effect schedule.
         *
         * After the `schedule` passes, the `newDelay` will get into effect immediately for every
         * new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}.
         *
         * A zero value only in `effectSchedule` indicates no pending delay change.
         *
         * NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay}
         * will be zero after the effect schedule.
         */
        function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule);
        /**
         * @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance
         * after the current timestamp plus a {defaultAdminDelay}.
         *
         * Requirements:
         *
         * - Only can be called by the current {defaultAdmin}.
         *
         * Emits a DefaultAdminRoleChangeStarted event.
         */
        function beginDefaultAdminTransfer(address newAdmin) external;
        /**
         * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
         *
         * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function.
         *
         * Requirements:
         *
         * - Only can be called by the current {defaultAdmin}.
         *
         * May emit a DefaultAdminTransferCanceled event.
         */
        function cancelDefaultAdminTransfer() external;
        /**
         * @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
         *
         * After calling the function:
         *
         * - `DEFAULT_ADMIN_ROLE` should be granted to the caller.
         * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder.
         * - {pendingDefaultAdmin} should be reset to zero values.
         *
         * Requirements:
         *
         * - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`.
         * - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed.
         */
        function acceptDefaultAdminTransfer() external;
        /**
         * @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting
         * into effect after the current timestamp plus a {defaultAdminDelay}.
         *
         * This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this
         * method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay}
         * set before calling.
         *
         * The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then
         * calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin}
         * complete transfer (including acceptance).
         *
         * The schedule is designed for two scenarios:
         *
         * - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by
         * {defaultAdminDelayIncreaseWait}.
         * - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`.
         *
         * A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change.
         *
         * Requirements:
         *
         * - Only can be called by the current {defaultAdmin}.
         *
         * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event.
         */
        function changeDefaultAdminDelay(uint48 newDelay) external;
        /**
         * @dev Cancels a scheduled {defaultAdminDelay} change.
         *
         * Requirements:
         *
         * - Only can be called by the current {defaultAdmin}.
         *
         * May emit a DefaultAdminDelayChangeCanceled event.
         */
        function rollbackDefaultAdminDelay() external;
        /**
         * @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay})
         * to take effect. Default to 5 days.
         *
         * When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with
         * the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds)
         * that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can
         * be overrode for a custom {defaultAdminDelay} increase scheduling.
         *
         * IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise,
         * there's a risk of setting a high new delay that goes into effect almost immediately without the
         * possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds).
         */
        function defaultAdminDelayIncreaseWait() external view returns (uint48);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
    pragma solidity ^0.8.20;
    import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
    import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
    import {ERC165Upgradeable} from "../utils/introspection/ERC165Upgradeable.sol";
    import {Initializable} from "../proxy/utils/Initializable.sol";
    /**
     * @dev Contract module that allows children to implement role-based access
     * control mechanisms. This is a lightweight version that doesn't allow enumerating role
     * members except through off-chain means by accessing the contract event logs. Some
     * applications may benefit from on-chain enumerability, for those cases see
     * {AccessControlEnumerable}.
     *
     * Roles are referred to by their `bytes32` identifier. These should be exposed
     * in the external API and be unique. The best way to achieve this is by
     * using `public constant` hash digests:
     *
     * ```solidity
     * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
     * ```
     *
     * Roles can be used to represent a set of permissions. To restrict access to a
     * function call, use {hasRole}:
     *
     * ```solidity
     * function foo() public {
     *     require(hasRole(MY_ROLE, msg.sender));
     *     ...
     * }
     * ```
     *
     * Roles can be granted and revoked dynamically via the {grantRole} and
     * {revokeRole} functions. Each role has an associated admin role, and only
     * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
     *
     * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
     * that only accounts with this role will be able to grant or revoke other
     * roles. More complex role relationships can be created by using
     * {_setRoleAdmin}.
     *
     * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
     * grant and revoke this role. Extra precautions should be taken to secure
     * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
     * to enforce additional security measures for this role.
     */
    abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {
        struct RoleData {
            mapping(address account => bool) hasRole;
            bytes32 adminRole;
        }
        bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
        /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl
        struct AccessControlStorage {
            mapping(bytes32 role => RoleData) _roles;
        }
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.AccessControl")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;
        function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {
            assembly {
                $.slot := AccessControlStorageLocation
            }
        }
        /**
         * @dev Modifier that checks that an account has a specific role. Reverts
         * with an {AccessControlUnauthorizedAccount} error including the required role.
         */
        modifier onlyRole(bytes32 role) {
            _checkRole(role);
            _;
        }
        function __AccessControl_init() internal onlyInitializing {
        }
        function __AccessControl_init_unchained() internal onlyInitializing {
        }
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
        }
        /**
         * @dev Returns `true` if `account` has been granted `role`.
         */
        function hasRole(bytes32 role, address account) public view virtual returns (bool) {
            AccessControlStorage storage $ = _getAccessControlStorage();
            return $._roles[role].hasRole[account];
        }
        /**
         * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
         * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
         */
        function _checkRole(bytes32 role) internal view virtual {
            _checkRole(role, _msgSender());
        }
        /**
         * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
         * is missing `role`.
         */
        function _checkRole(bytes32 role, address account) internal view virtual {
            if (!hasRole(role, account)) {
                revert AccessControlUnauthorizedAccount(account, role);
            }
        }
        /**
         * @dev Returns the admin role that controls `role`. See {grantRole} and
         * {revokeRole}.
         *
         * To change a role's admin, use {_setRoleAdmin}.
         */
        function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
            AccessControlStorage storage $ = _getAccessControlStorage();
            return $._roles[role].adminRole;
        }
        /**
         * @dev Grants `role` to `account`.
         *
         * If `account` had not been already granted `role`, emits a {RoleGranted}
         * event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         *
         * May emit a {RoleGranted} event.
         */
        function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
            _grantRole(role, account);
        }
        /**
         * @dev Revokes `role` from `account`.
         *
         * If `account` had been granted `role`, emits a {RoleRevoked} event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         *
         * May emit a {RoleRevoked} event.
         */
        function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
            _revokeRole(role, account);
        }
        /**
         * @dev Revokes `role` from the calling account.
         *
         * Roles are often managed via {grantRole} and {revokeRole}: this function's
         * purpose is to provide a mechanism for accounts to lose their privileges
         * if they are compromised (such as when a trusted device is misplaced).
         *
         * If the calling account had been revoked `role`, emits a {RoleRevoked}
         * event.
         *
         * Requirements:
         *
         * - the caller must be `callerConfirmation`.
         *
         * May emit a {RoleRevoked} event.
         */
        function renounceRole(bytes32 role, address callerConfirmation) public virtual {
            if (callerConfirmation != _msgSender()) {
                revert AccessControlBadConfirmation();
            }
            _revokeRole(role, callerConfirmation);
        }
        /**
         * @dev Sets `adminRole` as ``role``'s admin role.
         *
         * Emits a {RoleAdminChanged} event.
         */
        function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
            AccessControlStorage storage $ = _getAccessControlStorage();
            bytes32 previousAdminRole = getRoleAdmin(role);
            $._roles[role].adminRole = adminRole;
            emit RoleAdminChanged(role, previousAdminRole, adminRole);
        }
        /**
         * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
         *
         * Internal function without access restriction.
         *
         * May emit a {RoleGranted} event.
         */
        function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
            AccessControlStorage storage $ = _getAccessControlStorage();
            if (!hasRole(role, account)) {
                $._roles[role].hasRole[account] = true;
                emit RoleGranted(role, account, _msgSender());
                return true;
            } else {
                return false;
            }
        }
        /**
         * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
         *
         * Internal function without access restriction.
         *
         * May emit a {RoleRevoked} event.
         */
        function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
            AccessControlStorage storage $ = _getAccessControlStorage();
            if (hasRole(role, account)) {
                $._roles[role].hasRole[account] = false;
                emit RoleRevoked(role, account, _msgSender());
                return true;
            } else {
                return false;
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev External interface of AccessControl declared to support ERC165 detection.
     */
    interface IAccessControl {
        /**
         * @dev The `account` is missing a role.
         */
        error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
        /**
         * @dev The caller of a function is not the expected one.
         *
         * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
         */
        error AccessControlBadConfirmation();
        /**
         * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
         *
         * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
         * {RoleAdminChanged} not being emitted signaling this.
         */
        event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
        /**
         * @dev Emitted when `account` is granted `role`.
         *
         * `sender` is the account that originated the contract call, an admin role
         * bearer except when using {AccessControl-_setupRole}.
         */
        event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
        /**
         * @dev Emitted when `account` is revoked `role`.
         *
         * `sender` is the account that originated the contract call:
         *   - if using `revokeRole`, it is the admin role bearer
         *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
         */
        event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
        /**
         * @dev Returns `true` if `account` has been granted `role`.
         */
        function hasRole(bytes32 role, address account) external view returns (bool);
        /**
         * @dev Returns the admin role that controls `role`. See {grantRole} and
         * {revokeRole}.
         *
         * To change a role's admin, use {AccessControl-_setRoleAdmin}.
         */
        function getRoleAdmin(bytes32 role) external view returns (bytes32);
        /**
         * @dev Grants `role` to `account`.
         *
         * If `account` had not been already granted `role`, emits a {RoleGranted}
         * event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         */
        function grantRole(bytes32 role, address account) external;
        /**
         * @dev Revokes `role` from `account`.
         *
         * If `account` had been granted `role`, emits a {RoleRevoked} event.
         *
         * Requirements:
         *
         * - the caller must have ``role``'s admin role.
         */
        function revokeRole(bytes32 role, address account) external;
        /**
         * @dev Revokes `role` from the calling account.
         *
         * Roles are often managed via {grantRole} and {revokeRole}: this function's
         * purpose is to provide a mechanism for accounts to lose their privileges
         * if they are compromised (such as when a trusted device is misplaced).
         *
         * If the calling account had been granted `role`, emits a {RoleRevoked}
         * event.
         *
         * Requirements:
         *
         * - the caller must be `callerConfirmation`.
         */
        function renounceRole(bytes32 role, address callerConfirmation) external;
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
    // This file was procedurally generated from scripts/generate/templates/SafeCast.js.
    pragma solidity ^0.8.20;
    /**
     * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
     * checks.
     *
     * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
     * easily result in undesired exploitation or bugs, since developers usually
     * assume that overflows raise errors. `SafeCast` restores this intuition by
     * reverting the transaction when such an operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeCast {
        /**
         * @dev Value doesn't fit in an uint of `bits` size.
         */
        error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
        /**
         * @dev An int value doesn't fit in an uint of `bits` size.
         */
        error SafeCastOverflowedIntToUint(int256 value);
        /**
         * @dev Value doesn't fit in an int of `bits` size.
         */
        error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
        /**
         * @dev An uint value doesn't fit in an int of `bits` size.
         */
        error SafeCastOverflowedUintToInt(uint256 value);
        /**
         * @dev Returns the downcasted uint248 from uint256, reverting on
         * overflow (when the input is greater than largest uint248).
         *
         * Counterpart to Solidity's `uint248` operator.
         *
         * Requirements:
         *
         * - input must fit into 248 bits
         */
        function toUint248(uint256 value) internal pure returns (uint248) {
            if (value > type(uint248).max) {
                revert SafeCastOverflowedUintDowncast(248, value);
            }
            return uint248(value);
        }
        /**
         * @dev Returns the downcasted uint240 from uint256, reverting on
         * overflow (when the input is greater than largest uint240).
         *
         * Counterpart to Solidity's `uint240` operator.
         *
         * Requirements:
         *
         * - input must fit into 240 bits
         */
        function toUint240(uint256 value) internal pure returns (uint240) {
            if (value > type(uint240).max) {
                revert SafeCastOverflowedUintDowncast(240, value);
            }
            return uint240(value);
        }
        /**
         * @dev Returns the downcasted uint232 from uint256, reverting on
         * overflow (when the input is greater than largest uint232).
         *
         * Counterpart to Solidity's `uint232` operator.
         *
         * Requirements:
         *
         * - input must fit into 232 bits
         */
        function toUint232(uint256 value) internal pure returns (uint232) {
            if (value > type(uint232).max) {
                revert SafeCastOverflowedUintDowncast(232, value);
            }
            return uint232(value);
        }
        /**
         * @dev Returns the downcasted uint224 from uint256, reverting on
         * overflow (when the input is greater than largest uint224).
         *
         * Counterpart to Solidity's `uint224` operator.
         *
         * Requirements:
         *
         * - input must fit into 224 bits
         */
        function toUint224(uint256 value) internal pure returns (uint224) {
            if (value > type(uint224).max) {
                revert SafeCastOverflowedUintDowncast(224, value);
            }
            return uint224(value);
        }
        /**
         * @dev Returns the downcasted uint216 from uint256, reverting on
         * overflow (when the input is greater than largest uint216).
         *
         * Counterpart to Solidity's `uint216` operator.
         *
         * Requirements:
         *
         * - input must fit into 216 bits
         */
        function toUint216(uint256 value) internal pure returns (uint216) {
            if (value > type(uint216).max) {
                revert SafeCastOverflowedUintDowncast(216, value);
            }
            return uint216(value);
        }
        /**
         * @dev Returns the downcasted uint208 from uint256, reverting on
         * overflow (when the input is greater than largest uint208).
         *
         * Counterpart to Solidity's `uint208` operator.
         *
         * Requirements:
         *
         * - input must fit into 208 bits
         */
        function toUint208(uint256 value) internal pure returns (uint208) {
            if (value > type(uint208).max) {
                revert SafeCastOverflowedUintDowncast(208, value);
            }
            return uint208(value);
        }
        /**
         * @dev Returns the downcasted uint200 from uint256, reverting on
         * overflow (when the input is greater than largest uint200).
         *
         * Counterpart to Solidity's `uint200` operator.
         *
         * Requirements:
         *
         * - input must fit into 200 bits
         */
        function toUint200(uint256 value) internal pure returns (uint200) {
            if (value > type(uint200).max) {
                revert SafeCastOverflowedUintDowncast(200, value);
            }
            return uint200(value);
        }
        /**
         * @dev Returns the downcasted uint192 from uint256, reverting on
         * overflow (when the input is greater than largest uint192).
         *
         * Counterpart to Solidity's `uint192` operator.
         *
         * Requirements:
         *
         * - input must fit into 192 bits
         */
        function toUint192(uint256 value) internal pure returns (uint192) {
            if (value > type(uint192).max) {
                revert SafeCastOverflowedUintDowncast(192, value);
            }
            return uint192(value);
        }
        /**
         * @dev Returns the downcasted uint184 from uint256, reverting on
         * overflow (when the input is greater than largest uint184).
         *
         * Counterpart to Solidity's `uint184` operator.
         *
         * Requirements:
         *
         * - input must fit into 184 bits
         */
        function toUint184(uint256 value) internal pure returns (uint184) {
            if (value > type(uint184).max) {
                revert SafeCastOverflowedUintDowncast(184, value);
            }
            return uint184(value);
        }
        /**
         * @dev Returns the downcasted uint176 from uint256, reverting on
         * overflow (when the input is greater than largest uint176).
         *
         * Counterpart to Solidity's `uint176` operator.
         *
         * Requirements:
         *
         * - input must fit into 176 bits
         */
        function toUint176(uint256 value) internal pure returns (uint176) {
            if (value > type(uint176).max) {
                revert SafeCastOverflowedUintDowncast(176, value);
            }
            return uint176(value);
        }
        /**
         * @dev Returns the downcasted uint168 from uint256, reverting on
         * overflow (when the input is greater than largest uint168).
         *
         * Counterpart to Solidity's `uint168` operator.
         *
         * Requirements:
         *
         * - input must fit into 168 bits
         */
        function toUint168(uint256 value) internal pure returns (uint168) {
            if (value > type(uint168).max) {
                revert SafeCastOverflowedUintDowncast(168, value);
            }
            return uint168(value);
        }
        /**
         * @dev Returns the downcasted uint160 from uint256, reverting on
         * overflow (when the input is greater than largest uint160).
         *
         * Counterpart to Solidity's `uint160` operator.
         *
         * Requirements:
         *
         * - input must fit into 160 bits
         */
        function toUint160(uint256 value) internal pure returns (uint160) {
            if (value > type(uint160).max) {
                revert SafeCastOverflowedUintDowncast(160, value);
            }
            return uint160(value);
        }
        /**
         * @dev Returns the downcasted uint152 from uint256, reverting on
         * overflow (when the input is greater than largest uint152).
         *
         * Counterpart to Solidity's `uint152` operator.
         *
         * Requirements:
         *
         * - input must fit into 152 bits
         */
        function toUint152(uint256 value) internal pure returns (uint152) {
            if (value > type(uint152).max) {
                revert SafeCastOverflowedUintDowncast(152, value);
            }
            return uint152(value);
        }
        /**
         * @dev Returns the downcasted uint144 from uint256, reverting on
         * overflow (when the input is greater than largest uint144).
         *
         * Counterpart to Solidity's `uint144` operator.
         *
         * Requirements:
         *
         * - input must fit into 144 bits
         */
        function toUint144(uint256 value) internal pure returns (uint144) {
            if (value > type(uint144).max) {
                revert SafeCastOverflowedUintDowncast(144, value);
            }
            return uint144(value);
        }
        /**
         * @dev Returns the downcasted uint136 from uint256, reverting on
         * overflow (when the input is greater than largest uint136).
         *
         * Counterpart to Solidity's `uint136` operator.
         *
         * Requirements:
         *
         * - input must fit into 136 bits
         */
        function toUint136(uint256 value) internal pure returns (uint136) {
            if (value > type(uint136).max) {
                revert SafeCastOverflowedUintDowncast(136, value);
            }
            return uint136(value);
        }
        /**
         * @dev Returns the downcasted uint128 from uint256, reverting on
         * overflow (when the input is greater than largest uint128).
         *
         * Counterpart to Solidity's `uint128` operator.
         *
         * Requirements:
         *
         * - input must fit into 128 bits
         */
        function toUint128(uint256 value) internal pure returns (uint128) {
            if (value > type(uint128).max) {
                revert SafeCastOverflowedUintDowncast(128, value);
            }
            return uint128(value);
        }
        /**
         * @dev Returns the downcasted uint120 from uint256, reverting on
         * overflow (when the input is greater than largest uint120).
         *
         * Counterpart to Solidity's `uint120` operator.
         *
         * Requirements:
         *
         * - input must fit into 120 bits
         */
        function toUint120(uint256 value) internal pure returns (uint120) {
            if (value > type(uint120).max) {
                revert SafeCastOverflowedUintDowncast(120, value);
            }
            return uint120(value);
        }
        /**
         * @dev Returns the downcasted uint112 from uint256, reverting on
         * overflow (when the input is greater than largest uint112).
         *
         * Counterpart to Solidity's `uint112` operator.
         *
         * Requirements:
         *
         * - input must fit into 112 bits
         */
        function toUint112(uint256 value) internal pure returns (uint112) {
            if (value > type(uint112).max) {
                revert SafeCastOverflowedUintDowncast(112, value);
            }
            return uint112(value);
        }
        /**
         * @dev Returns the downcasted uint104 from uint256, reverting on
         * overflow (when the input is greater than largest uint104).
         *
         * Counterpart to Solidity's `uint104` operator.
         *
         * Requirements:
         *
         * - input must fit into 104 bits
         */
        function toUint104(uint256 value) internal pure returns (uint104) {
            if (value > type(uint104).max) {
                revert SafeCastOverflowedUintDowncast(104, value);
            }
            return uint104(value);
        }
        /**
         * @dev Returns the downcasted uint96 from uint256, reverting on
         * overflow (when the input is greater than largest uint96).
         *
         * Counterpart to Solidity's `uint96` operator.
         *
         * Requirements:
         *
         * - input must fit into 96 bits
         */
        function toUint96(uint256 value) internal pure returns (uint96) {
            if (value > type(uint96).max) {
                revert SafeCastOverflowedUintDowncast(96, value);
            }
            return uint96(value);
        }
        /**
         * @dev Returns the downcasted uint88 from uint256, reverting on
         * overflow (when the input is greater than largest uint88).
         *
         * Counterpart to Solidity's `uint88` operator.
         *
         * Requirements:
         *
         * - input must fit into 88 bits
         */
        function toUint88(uint256 value) internal pure returns (uint88) {
            if (value > type(uint88).max) {
                revert SafeCastOverflowedUintDowncast(88, value);
            }
            return uint88(value);
        }
        /**
         * @dev Returns the downcasted uint80 from uint256, reverting on
         * overflow (when the input is greater than largest uint80).
         *
         * Counterpart to Solidity's `uint80` operator.
         *
         * Requirements:
         *
         * - input must fit into 80 bits
         */
        function toUint80(uint256 value) internal pure returns (uint80) {
            if (value > type(uint80).max) {
                revert SafeCastOverflowedUintDowncast(80, value);
            }
            return uint80(value);
        }
        /**
         * @dev Returns the downcasted uint72 from uint256, reverting on
         * overflow (when the input is greater than largest uint72).
         *
         * Counterpart to Solidity's `uint72` operator.
         *
         * Requirements:
         *
         * - input must fit into 72 bits
         */
        function toUint72(uint256 value) internal pure returns (uint72) {
            if (value > type(uint72).max) {
                revert SafeCastOverflowedUintDowncast(72, value);
            }
            return uint72(value);
        }
        /**
         * @dev Returns the downcasted uint64 from uint256, reverting on
         * overflow (when the input is greater than largest uint64).
         *
         * Counterpart to Solidity's `uint64` operator.
         *
         * Requirements:
         *
         * - input must fit into 64 bits
         */
        function toUint64(uint256 value) internal pure returns (uint64) {
            if (value > type(uint64).max) {
                revert SafeCastOverflowedUintDowncast(64, value);
            }
            return uint64(value);
        }
        /**
         * @dev Returns the downcasted uint56 from uint256, reverting on
         * overflow (when the input is greater than largest uint56).
         *
         * Counterpart to Solidity's `uint56` operator.
         *
         * Requirements:
         *
         * - input must fit into 56 bits
         */
        function toUint56(uint256 value) internal pure returns (uint56) {
            if (value > type(uint56).max) {
                revert SafeCastOverflowedUintDowncast(56, value);
            }
            return uint56(value);
        }
        /**
         * @dev Returns the downcasted uint48 from uint256, reverting on
         * overflow (when the input is greater than largest uint48).
         *
         * Counterpart to Solidity's `uint48` operator.
         *
         * Requirements:
         *
         * - input must fit into 48 bits
         */
        function toUint48(uint256 value) internal pure returns (uint48) {
            if (value > type(uint48).max) {
                revert SafeCastOverflowedUintDowncast(48, value);
            }
            return uint48(value);
        }
        /**
         * @dev Returns the downcasted uint40 from uint256, reverting on
         * overflow (when the input is greater than largest uint40).
         *
         * Counterpart to Solidity's `uint40` operator.
         *
         * Requirements:
         *
         * - input must fit into 40 bits
         */
        function toUint40(uint256 value) internal pure returns (uint40) {
            if (value > type(uint40).max) {
                revert SafeCastOverflowedUintDowncast(40, value);
            }
            return uint40(value);
        }
        /**
         * @dev Returns the downcasted uint32 from uint256, reverting on
         * overflow (when the input is greater than largest uint32).
         *
         * Counterpart to Solidity's `uint32` operator.
         *
         * Requirements:
         *
         * - input must fit into 32 bits
         */
        function toUint32(uint256 value) internal pure returns (uint32) {
            if (value > type(uint32).max) {
                revert SafeCastOverflowedUintDowncast(32, value);
            }
            return uint32(value);
        }
        /**
         * @dev Returns the downcasted uint24 from uint256, reverting on
         * overflow (when the input is greater than largest uint24).
         *
         * Counterpart to Solidity's `uint24` operator.
         *
         * Requirements:
         *
         * - input must fit into 24 bits
         */
        function toUint24(uint256 value) internal pure returns (uint24) {
            if (value > type(uint24).max) {
                revert SafeCastOverflowedUintDowncast(24, value);
            }
            return uint24(value);
        }
        /**
         * @dev Returns the downcasted uint16 from uint256, reverting on
         * overflow (when the input is greater than largest uint16).
         *
         * Counterpart to Solidity's `uint16` operator.
         *
         * Requirements:
         *
         * - input must fit into 16 bits
         */
        function toUint16(uint256 value) internal pure returns (uint16) {
            if (value > type(uint16).max) {
                revert SafeCastOverflowedUintDowncast(16, value);
            }
            return uint16(value);
        }
        /**
         * @dev Returns the downcasted uint8 from uint256, reverting on
         * overflow (when the input is greater than largest uint8).
         *
         * Counterpart to Solidity's `uint8` operator.
         *
         * Requirements:
         *
         * - input must fit into 8 bits
         */
        function toUint8(uint256 value) internal pure returns (uint8) {
            if (value > type(uint8).max) {
                revert SafeCastOverflowedUintDowncast(8, value);
            }
            return uint8(value);
        }
        /**
         * @dev Converts a signed int256 into an unsigned uint256.
         *
         * Requirements:
         *
         * - input must be greater than or equal to 0.
         */
        function toUint256(int256 value) internal pure returns (uint256) {
            if (value < 0) {
                revert SafeCastOverflowedIntToUint(value);
            }
            return uint256(value);
        }
        /**
         * @dev Returns the downcasted int248 from int256, reverting on
         * overflow (when the input is less than smallest int248 or
         * greater than largest int248).
         *
         * Counterpart to Solidity's `int248` operator.
         *
         * Requirements:
         *
         * - input must fit into 248 bits
         */
        function toInt248(int256 value) internal pure returns (int248 downcasted) {
            downcasted = int248(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(248, value);
            }
        }
        /**
         * @dev Returns the downcasted int240 from int256, reverting on
         * overflow (when the input is less than smallest int240 or
         * greater than largest int240).
         *
         * Counterpart to Solidity's `int240` operator.
         *
         * Requirements:
         *
         * - input must fit into 240 bits
         */
        function toInt240(int256 value) internal pure returns (int240 downcasted) {
            downcasted = int240(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(240, value);
            }
        }
        /**
         * @dev Returns the downcasted int232 from int256, reverting on
         * overflow (when the input is less than smallest int232 or
         * greater than largest int232).
         *
         * Counterpart to Solidity's `int232` operator.
         *
         * Requirements:
         *
         * - input must fit into 232 bits
         */
        function toInt232(int256 value) internal pure returns (int232 downcasted) {
            downcasted = int232(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(232, value);
            }
        }
        /**
         * @dev Returns the downcasted int224 from int256, reverting on
         * overflow (when the input is less than smallest int224 or
         * greater than largest int224).
         *
         * Counterpart to Solidity's `int224` operator.
         *
         * Requirements:
         *
         * - input must fit into 224 bits
         */
        function toInt224(int256 value) internal pure returns (int224 downcasted) {
            downcasted = int224(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(224, value);
            }
        }
        /**
         * @dev Returns the downcasted int216 from int256, reverting on
         * overflow (when the input is less than smallest int216 or
         * greater than largest int216).
         *
         * Counterpart to Solidity's `int216` operator.
         *
         * Requirements:
         *
         * - input must fit into 216 bits
         */
        function toInt216(int256 value) internal pure returns (int216 downcasted) {
            downcasted = int216(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(216, value);
            }
        }
        /**
         * @dev Returns the downcasted int208 from int256, reverting on
         * overflow (when the input is less than smallest int208 or
         * greater than largest int208).
         *
         * Counterpart to Solidity's `int208` operator.
         *
         * Requirements:
         *
         * - input must fit into 208 bits
         */
        function toInt208(int256 value) internal pure returns (int208 downcasted) {
            downcasted = int208(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(208, value);
            }
        }
        /**
         * @dev Returns the downcasted int200 from int256, reverting on
         * overflow (when the input is less than smallest int200 or
         * greater than largest int200).
         *
         * Counterpart to Solidity's `int200` operator.
         *
         * Requirements:
         *
         * - input must fit into 200 bits
         */
        function toInt200(int256 value) internal pure returns (int200 downcasted) {
            downcasted = int200(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(200, value);
            }
        }
        /**
         * @dev Returns the downcasted int192 from int256, reverting on
         * overflow (when the input is less than smallest int192 or
         * greater than largest int192).
         *
         * Counterpart to Solidity's `int192` operator.
         *
         * Requirements:
         *
         * - input must fit into 192 bits
         */
        function toInt192(int256 value) internal pure returns (int192 downcasted) {
            downcasted = int192(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(192, value);
            }
        }
        /**
         * @dev Returns the downcasted int184 from int256, reverting on
         * overflow (when the input is less than smallest int184 or
         * greater than largest int184).
         *
         * Counterpart to Solidity's `int184` operator.
         *
         * Requirements:
         *
         * - input must fit into 184 bits
         */
        function toInt184(int256 value) internal pure returns (int184 downcasted) {
            downcasted = int184(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(184, value);
            }
        }
        /**
         * @dev Returns the downcasted int176 from int256, reverting on
         * overflow (when the input is less than smallest int176 or
         * greater than largest int176).
         *
         * Counterpart to Solidity's `int176` operator.
         *
         * Requirements:
         *
         * - input must fit into 176 bits
         */
        function toInt176(int256 value) internal pure returns (int176 downcasted) {
            downcasted = int176(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(176, value);
            }
        }
        /**
         * @dev Returns the downcasted int168 from int256, reverting on
         * overflow (when the input is less than smallest int168 or
         * greater than largest int168).
         *
         * Counterpart to Solidity's `int168` operator.
         *
         * Requirements:
         *
         * - input must fit into 168 bits
         */
        function toInt168(int256 value) internal pure returns (int168 downcasted) {
            downcasted = int168(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(168, value);
            }
        }
        /**
         * @dev Returns the downcasted int160 from int256, reverting on
         * overflow (when the input is less than smallest int160 or
         * greater than largest int160).
         *
         * Counterpart to Solidity's `int160` operator.
         *
         * Requirements:
         *
         * - input must fit into 160 bits
         */
        function toInt160(int256 value) internal pure returns (int160 downcasted) {
            downcasted = int160(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(160, value);
            }
        }
        /**
         * @dev Returns the downcasted int152 from int256, reverting on
         * overflow (when the input is less than smallest int152 or
         * greater than largest int152).
         *
         * Counterpart to Solidity's `int152` operator.
         *
         * Requirements:
         *
         * - input must fit into 152 bits
         */
        function toInt152(int256 value) internal pure returns (int152 downcasted) {
            downcasted = int152(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(152, value);
            }
        }
        /**
         * @dev Returns the downcasted int144 from int256, reverting on
         * overflow (when the input is less than smallest int144 or
         * greater than largest int144).
         *
         * Counterpart to Solidity's `int144` operator.
         *
         * Requirements:
         *
         * - input must fit into 144 bits
         */
        function toInt144(int256 value) internal pure returns (int144 downcasted) {
            downcasted = int144(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(144, value);
            }
        }
        /**
         * @dev Returns the downcasted int136 from int256, reverting on
         * overflow (when the input is less than smallest int136 or
         * greater than largest int136).
         *
         * Counterpart to Solidity's `int136` operator.
         *
         * Requirements:
         *
         * - input must fit into 136 bits
         */
        function toInt136(int256 value) internal pure returns (int136 downcasted) {
            downcasted = int136(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(136, value);
            }
        }
        /**
         * @dev Returns the downcasted int128 from int256, reverting on
         * overflow (when the input is less than smallest int128 or
         * greater than largest int128).
         *
         * Counterpart to Solidity's `int128` operator.
         *
         * Requirements:
         *
         * - input must fit into 128 bits
         */
        function toInt128(int256 value) internal pure returns (int128 downcasted) {
            downcasted = int128(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(128, value);
            }
        }
        /**
         * @dev Returns the downcasted int120 from int256, reverting on
         * overflow (when the input is less than smallest int120 or
         * greater than largest int120).
         *
         * Counterpart to Solidity's `int120` operator.
         *
         * Requirements:
         *
         * - input must fit into 120 bits
         */
        function toInt120(int256 value) internal pure returns (int120 downcasted) {
            downcasted = int120(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(120, value);
            }
        }
        /**
         * @dev Returns the downcasted int112 from int256, reverting on
         * overflow (when the input is less than smallest int112 or
         * greater than largest int112).
         *
         * Counterpart to Solidity's `int112` operator.
         *
         * Requirements:
         *
         * - input must fit into 112 bits
         */
        function toInt112(int256 value) internal pure returns (int112 downcasted) {
            downcasted = int112(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(112, value);
            }
        }
        /**
         * @dev Returns the downcasted int104 from int256, reverting on
         * overflow (when the input is less than smallest int104 or
         * greater than largest int104).
         *
         * Counterpart to Solidity's `int104` operator.
         *
         * Requirements:
         *
         * - input must fit into 104 bits
         */
        function toInt104(int256 value) internal pure returns (int104 downcasted) {
            downcasted = int104(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(104, value);
            }
        }
        /**
         * @dev Returns the downcasted int96 from int256, reverting on
         * overflow (when the input is less than smallest int96 or
         * greater than largest int96).
         *
         * Counterpart to Solidity's `int96` operator.
         *
         * Requirements:
         *
         * - input must fit into 96 bits
         */
        function toInt96(int256 value) internal pure returns (int96 downcasted) {
            downcasted = int96(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(96, value);
            }
        }
        /**
         * @dev Returns the downcasted int88 from int256, reverting on
         * overflow (when the input is less than smallest int88 or
         * greater than largest int88).
         *
         * Counterpart to Solidity's `int88` operator.
         *
         * Requirements:
         *
         * - input must fit into 88 bits
         */
        function toInt88(int256 value) internal pure returns (int88 downcasted) {
            downcasted = int88(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(88, value);
            }
        }
        /**
         * @dev Returns the downcasted int80 from int256, reverting on
         * overflow (when the input is less than smallest int80 or
         * greater than largest int80).
         *
         * Counterpart to Solidity's `int80` operator.
         *
         * Requirements:
         *
         * - input must fit into 80 bits
         */
        function toInt80(int256 value) internal pure returns (int80 downcasted) {
            downcasted = int80(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(80, value);
            }
        }
        /**
         * @dev Returns the downcasted int72 from int256, reverting on
         * overflow (when the input is less than smallest int72 or
         * greater than largest int72).
         *
         * Counterpart to Solidity's `int72` operator.
         *
         * Requirements:
         *
         * - input must fit into 72 bits
         */
        function toInt72(int256 value) internal pure returns (int72 downcasted) {
            downcasted = int72(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(72, value);
            }
        }
        /**
         * @dev Returns the downcasted int64 from int256, reverting on
         * overflow (when the input is less than smallest int64 or
         * greater than largest int64).
         *
         * Counterpart to Solidity's `int64` operator.
         *
         * Requirements:
         *
         * - input must fit into 64 bits
         */
        function toInt64(int256 value) internal pure returns (int64 downcasted) {
            downcasted = int64(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(64, value);
            }
        }
        /**
         * @dev Returns the downcasted int56 from int256, reverting on
         * overflow (when the input is less than smallest int56 or
         * greater than largest int56).
         *
         * Counterpart to Solidity's `int56` operator.
         *
         * Requirements:
         *
         * - input must fit into 56 bits
         */
        function toInt56(int256 value) internal pure returns (int56 downcasted) {
            downcasted = int56(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(56, value);
            }
        }
        /**
         * @dev Returns the downcasted int48 from int256, reverting on
         * overflow (when the input is less than smallest int48 or
         * greater than largest int48).
         *
         * Counterpart to Solidity's `int48` operator.
         *
         * Requirements:
         *
         * - input must fit into 48 bits
         */
        function toInt48(int256 value) internal pure returns (int48 downcasted) {
            downcasted = int48(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(48, value);
            }
        }
        /**
         * @dev Returns the downcasted int40 from int256, reverting on
         * overflow (when the input is less than smallest int40 or
         * greater than largest int40).
         *
         * Counterpart to Solidity's `int40` operator.
         *
         * Requirements:
         *
         * - input must fit into 40 bits
         */
        function toInt40(int256 value) internal pure returns (int40 downcasted) {
            downcasted = int40(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(40, value);
            }
        }
        /**
         * @dev Returns the downcasted int32 from int256, reverting on
         * overflow (when the input is less than smallest int32 or
         * greater than largest int32).
         *
         * Counterpart to Solidity's `int32` operator.
         *
         * Requirements:
         *
         * - input must fit into 32 bits
         */
        function toInt32(int256 value) internal pure returns (int32 downcasted) {
            downcasted = int32(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(32, value);
            }
        }
        /**
         * @dev Returns the downcasted int24 from int256, reverting on
         * overflow (when the input is less than smallest int24 or
         * greater than largest int24).
         *
         * Counterpart to Solidity's `int24` operator.
         *
         * Requirements:
         *
         * - input must fit into 24 bits
         */
        function toInt24(int256 value) internal pure returns (int24 downcasted) {
            downcasted = int24(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(24, value);
            }
        }
        /**
         * @dev Returns the downcasted int16 from int256, reverting on
         * overflow (when the input is less than smallest int16 or
         * greater than largest int16).
         *
         * Counterpart to Solidity's `int16` operator.
         *
         * Requirements:
         *
         * - input must fit into 16 bits
         */
        function toInt16(int256 value) internal pure returns (int16 downcasted) {
            downcasted = int16(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(16, value);
            }
        }
        /**
         * @dev Returns the downcasted int8 from int256, reverting on
         * overflow (when the input is less than smallest int8 or
         * greater than largest int8).
         *
         * Counterpart to Solidity's `int8` operator.
         *
         * Requirements:
         *
         * - input must fit into 8 bits
         */
        function toInt8(int256 value) internal pure returns (int8 downcasted) {
            downcasted = int8(value);
            if (downcasted != value) {
                revert SafeCastOverflowedIntDowncast(8, value);
            }
        }
        /**
         * @dev Converts an unsigned uint256 into a signed int256.
         *
         * Requirements:
         *
         * - input must be less than or equal to maxInt256.
         */
        function toInt256(uint256 value) internal pure returns (int256) {
            // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
            if (value > uint256(type(int256).max)) {
                revert SafeCastOverflowedUintToInt(value);
            }
            return int256(value);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        /**
         * @dev Muldiv operation overflow.
         */
        error MathOverflowedMulDiv();
        enum Rounding {
            Floor, // Toward negative infinity
            Ceil, // Toward positive infinity
            Trunc, // Toward zero
            Expand // Away from zero
        }
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         */
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                uint256 c = a + b;
                if (c < a) return (false, 0);
                return (true, c);
            }
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
         */
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b > a) return (false, 0);
                return (true, a - b);
            }
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         */
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                // benefit is lost if 'b' is also tested.
                // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                if (a == 0) return (true, 0);
                uint256 c = a * b;
                if (c / a != b) return (false, 0);
                return (true, c);
            }
        }
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         */
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a / b);
            }
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         */
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            unchecked {
                if (b == 0) return (false, 0);
                return (true, a % b);
            }
        }
        /**
         * @dev Returns the largest of two numbers.
         */
        function max(uint256 a, uint256 b) internal pure returns (uint256) {
            return a > b ? a : b;
        }
        /**
         * @dev Returns the smallest of two numbers.
         */
        function min(uint256 a, uint256 b) internal pure returns (uint256) {
            return a < b ? a : b;
        }
        /**
         * @dev Returns the average of two numbers. The result is rounded towards
         * zero.
         */
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow.
            return (a & b) + (a ^ b) / 2;
        }
        /**
         * @dev Returns the ceiling of the division of two numbers.
         *
         * This differs from standard division with `/` in that it rounds towards infinity instead
         * of rounding towards zero.
         */
        function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
            if (b == 0) {
                // Guarantee the same behavior as in a regular Solidity division.
                return a / b;
            }
            // (a + b - 1) / b can overflow on addition, so we distribute.
            return a == 0 ? 0 : (a - 1) / b + 1;
        }
        /**
         * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
         * denominator == 0.
         * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
         * Uniswap Labs also under MIT license.
         */
        function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
            unchecked {
                // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                // variables such that product = prod1 * 2^256 + prod0.
                uint256 prod0 = x * y; // Least significant 256 bits of the product
                uint256 prod1; // Most significant 256 bits of the product
                assembly {
                    let mm := mulmod(x, y, not(0))
                    prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                }
                // Handle non-overflow cases, 256 by 256 division.
                if (prod1 == 0) {
                    // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                    // The surrounding unchecked block does not change this fact.
                    // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                    return prod0 / denominator;
                }
                // Make sure the result is less than 2^256. Also prevents denominator == 0.
                if (denominator <= prod1) {
                    revert MathOverflowedMulDiv();
                }
                ///////////////////////////////////////////////
                // 512 by 256 division.
                ///////////////////////////////////////////////
                // Make division exact by subtracting the remainder from [prod1 prod0].
                uint256 remainder;
                assembly {
                    // Compute remainder using mulmod.
                    remainder := mulmod(x, y, denominator)
                    // Subtract 256 bit number from 512 bit number.
                    prod1 := sub(prod1, gt(remainder, prod0))
                    prod0 := sub(prod0, remainder)
                }
                // Factor powers of two out of denominator and compute largest power of two divisor of denominator.
                // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
                uint256 twos = denominator & (0 - denominator);
                assembly {
                    // Divide denominator by twos.
                    denominator := div(denominator, twos)
                    // Divide [prod1 prod0] by twos.
                    prod0 := div(prod0, twos)
                    // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                    twos := add(div(sub(0, twos), twos), 1)
                }
                // Shift in bits from prod1 into prod0.
                prod0 |= prod1 * twos;
                // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                // four bits. That is, denominator * inv = 1 mod 2^4.
                uint256 inverse = (3 * denominator) ^ 2;
                // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
                // works in modular arithmetic, doubling the correct bits in each step.
                inverse *= 2 - denominator * inverse; // inverse mod 2^8
                inverse *= 2 - denominator * inverse; // inverse mod 2^16
                inverse *= 2 - denominator * inverse; // inverse mod 2^32
                inverse *= 2 - denominator * inverse; // inverse mod 2^64
                inverse *= 2 - denominator * inverse; // inverse mod 2^128
                inverse *= 2 - denominator * inverse; // inverse mod 2^256
                // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                // is no longer required.
                result = prod0 * inverse;
                return result;
            }
        }
        /**
         * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
         */
        function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
            uint256 result = mulDiv(x, y, denominator);
            if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
                result += 1;
            }
            return result;
        }
        /**
         * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
         * towards zero.
         *
         * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
         */
        function sqrt(uint256 a) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
            // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
            //
            // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
            // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
            //
            // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
            // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
            // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
            //
            // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
            uint256 result = 1 << (log2(a) >> 1);
            // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
            // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
            // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
            // into the expected uint128 result.
            unchecked {
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                return min(result, a / result);
            }
        }
        /**
         * @notice Calculates sqrt(a), following the selected rounding direction.
         */
        function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = sqrt(a);
                return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
            }
        }
        /**
         * @dev Return the log in base 2 of a positive value rounded towards zero.
         * Returns 0 if given 0.
         */
        function log2(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >> 128 > 0) {
                    value >>= 128;
                    result += 128;
                }
                if (value >> 64 > 0) {
                    value >>= 64;
                    result += 64;
                }
                if (value >> 32 > 0) {
                    value >>= 32;
                    result += 32;
                }
                if (value >> 16 > 0) {
                    value >>= 16;
                    result += 16;
                }
                if (value >> 8 > 0) {
                    value >>= 8;
                    result += 8;
                }
                if (value >> 4 > 0) {
                    value >>= 4;
                    result += 4;
                }
                if (value >> 2 > 0) {
                    value >>= 2;
                    result += 2;
                }
                if (value >> 1 > 0) {
                    result += 1;
                }
            }
            return result;
        }
        /**
         * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log2(value);
                return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
            }
        }
        /**
         * @dev Return the log in base 10 of a positive value rounded towards zero.
         * Returns 0 if given 0.
         */
        function log10(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >= 10 ** 64) {
                    value /= 10 ** 64;
                    result += 64;
                }
                if (value >= 10 ** 32) {
                    value /= 10 ** 32;
                    result += 32;
                }
                if (value >= 10 ** 16) {
                    value /= 10 ** 16;
                    result += 16;
                }
                if (value >= 10 ** 8) {
                    value /= 10 ** 8;
                    result += 8;
                }
                if (value >= 10 ** 4) {
                    value /= 10 ** 4;
                    result += 4;
                }
                if (value >= 10 ** 2) {
                    value /= 10 ** 2;
                    result += 2;
                }
                if (value >= 10 ** 1) {
                    result += 1;
                }
            }
            return result;
        }
        /**
         * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log10(value);
                return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
            }
        }
        /**
         * @dev Return the log in base 256 of a positive value rounded towards zero.
         * Returns 0 if given 0.
         *
         * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
         */
        function log256(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >> 128 > 0) {
                    value >>= 128;
                    result += 16;
                }
                if (value >> 64 > 0) {
                    value >>= 64;
                    result += 8;
                }
                if (value >> 32 > 0) {
                    value >>= 32;
                    result += 4;
                }
                if (value >> 16 > 0) {
                    value >>= 16;
                    result += 2;
                }
                if (value >> 8 > 0) {
                    result += 1;
                }
            }
            return result;
        }
        /**
         * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log256(value);
                return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
            }
        }
        /**
         * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
         */
        function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
            return uint8(rounding) % 2 == 1;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev Interface for the Light Contract Ownership Standard.
     *
     * A standardized minimal interface required to identify an account that controls a contract
     */
    interface IERC5313 {
        /**
         * @dev Gets the address of the owner.
         */
        function owner() external view returns (address);
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.22;
    /// @notice Enforces transfer restrictions
    /// @author Dinari (https://github.com/dinaricrypto/sbt-contracts/blob/main/src/ITransferRestrictor.sol)
    interface ITransferRestrictor {
        /// @notice Checks if the transfer is allowed
        /// @param from The address of the sender
        /// @param to The address of the recipient
        function requireNotRestricted(address from, address to) external view;
        /// @notice Checks if the transfer is allowed
        /// @param account The address of the account
        function isBlacklisted(address account) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    /// @notice Simple ERC20 + EIP-2612 implementation.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC20.sol)
    /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
    /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)
    ///
    /// @dev Note:
    /// - The ERC20 standard allows minting and transferring to and from the zero address,
    ///   minting and transferring zero tokens, as well as self-approvals.
    ///   For performance, this implementation WILL NOT revert for such actions.
    ///   Please add any checks with overrides if desired.
    /// - The `permit` function uses the ecrecover precompile (0x1).
    ///
    /// If you are overriding:
    /// - NEVER violate the ERC20 invariant:
    ///   the total sum of all balances must be equal to `totalSupply()`.
    /// - Check that the overridden function is actually used in the function you want to
    ///   change the behavior of. Much of the code has been manually inlined for performance.
    abstract contract ERC20 {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       CUSTOM ERRORS                        */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The total supply has overflowed.
        error TotalSupplyOverflow();
        /// @dev The allowance has overflowed.
        error AllowanceOverflow();
        /// @dev The allowance has underflowed.
        error AllowanceUnderflow();
        /// @dev Insufficient balance.
        error InsufficientBalance();
        /// @dev Insufficient allowance.
        error InsufficientAllowance();
        /// @dev The permit is invalid.
        error InvalidPermit();
        /// @dev The permit has expired.
        error PermitExpired();
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                           EVENTS                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Emitted when `amount` tokens is transferred from `from` to `to`.
        event Transfer(address indexed from, address indexed to, uint256 amount);
        /// @dev Emitted when `amount` tokens is approved by `owner` to be used by `spender`.
        event Approval(address indexed owner, address indexed spender, uint256 amount);
        /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
        uint256 private constant _TRANSFER_EVENT_SIGNATURE =
            0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
        /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
        uint256 private constant _APPROVAL_EVENT_SIGNATURE =
            0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          STORAGE                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev The storage slot for the total supply.
        uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
        /// @dev The balance slot of `owner` is given by:
        /// ```
        ///     mstore(0x0c, _BALANCE_SLOT_SEED)
        ///     mstore(0x00, owner)
        ///     let balanceSlot := keccak256(0x0c, 0x20)
        /// ```
        uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
        /// @dev The allowance slot of (`owner`, `spender`) is given by:
        /// ```
        ///     mstore(0x20, spender)
        ///     mstore(0x0c, _ALLOWANCE_SLOT_SEED)
        ///     mstore(0x00, owner)
        ///     let allowanceSlot := keccak256(0x0c, 0x34)
        /// ```
        uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;
        /// @dev The nonce slot of `owner` is given by:
        /// ```
        ///     mstore(0x0c, _NONCES_SLOT_SEED)
        ///     mstore(0x00, owner)
        ///     let nonceSlot := keccak256(0x0c, 0x20)
        /// ```
        uint256 private constant _NONCES_SLOT_SEED = 0x38377508;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         CONSTANTS                          */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev `(_NONCES_SLOT_SEED << 16) | 0x1901`.
        uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;
        /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`.
        bytes32 private constant _DOMAIN_TYPEHASH =
            0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
        /// @dev `keccak256("1")`.
        bytes32 private constant _VERSION_HASH =
            0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;
        /// @dev `keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)")`.
        bytes32 private constant _PERMIT_TYPEHASH =
            0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                       ERC20 METADATA                       */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Returns the name of the token.
        function name() public view virtual returns (string memory);
        /// @dev Returns the symbol of the token.
        function symbol() public view virtual returns (string memory);
        /// @dev Returns the decimals places of the token.
        function decimals() public view virtual returns (uint8) {
            return 18;
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                           ERC20                            */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Returns the amount of tokens in existence.
        function totalSupply() public view virtual returns (uint256 result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := sload(_TOTAL_SUPPLY_SLOT)
            }
        }
        /// @dev Returns the amount of tokens owned by `owner`.
        function balanceOf(address owner) public view virtual returns (uint256 result) {
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x0c, _BALANCE_SLOT_SEED)
                mstore(0x00, owner)
                result := sload(keccak256(0x0c, 0x20))
            }
        }
        /// @dev Returns the amount of tokens that `spender` can spend on behalf of `owner`.
        function allowance(address owner, address spender)
            public
            view
            virtual
            returns (uint256 result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                mstore(0x20, spender)
                mstore(0x0c, _ALLOWANCE_SLOT_SEED)
                mstore(0x00, owner)
                result := sload(keccak256(0x0c, 0x34))
            }
        }
        /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
        ///
        /// Emits a {Approval} event.
        function approve(address spender, uint256 amount) public virtual returns (bool) {
            /// @solidity memory-safe-assembly
            assembly {
                // Compute the allowance slot and store the amount.
                mstore(0x20, spender)
                mstore(0x0c, _ALLOWANCE_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x34), amount)
                // Emit the {Approval} event.
                mstore(0x00, amount)
                log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
            }
            return true;
        }
        /// @dev Transfer `amount` tokens from the caller to `to`.
        ///
        /// Requirements:
        /// - `from` must at least have `amount`.
        ///
        /// Emits a {Transfer} event.
        function transfer(address to, uint256 amount) public virtual returns (bool) {
            _beforeTokenTransfer(msg.sender, to, amount);
            /// @solidity memory-safe-assembly
            assembly {
                // Compute the balance slot and load its value.
                mstore(0x0c, _BALANCE_SLOT_SEED)
                mstore(0x00, caller())
                let fromBalanceSlot := keccak256(0x0c, 0x20)
                let fromBalance := sload(fromBalanceSlot)
                // Revert if insufficient balance.
                if gt(amount, fromBalance) {
                    mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated balance.
                sstore(fromBalanceSlot, sub(fromBalance, amount))
                // Compute the balance slot of `to`.
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x20)
                // Add and store the updated balance of `to`.
                // Will not overflow because the sum of all user balances
                // cannot exceed the maximum uint256 value.
                sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
                // Emit the {Transfer} event.
                mstore(0x20, amount)
                log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
            }
            _afterTokenTransfer(msg.sender, to, amount);
            return true;
        }
        /// @dev Transfers `amount` tokens from `from` to `to`.
        ///
        /// Note: Does not update the allowance if it is the maximum uint256 value.
        ///
        /// Requirements:
        /// - `from` must at least have `amount`.
        /// - The caller must have at least `amount` of allowance to transfer the tokens of `from`.
        ///
        /// Emits a {Transfer} event.
        function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
            _beforeTokenTransfer(from, to, amount);
            /// @solidity memory-safe-assembly
            assembly {
                let from_ := shl(96, from)
                // Compute the allowance slot and load its value.
                mstore(0x20, caller())
                mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
                let allowanceSlot := keccak256(0x0c, 0x34)
                let allowance_ := sload(allowanceSlot)
                // If the allowance is not the maximum uint256 value.
                if add(allowance_, 1) {
                    // Revert if the amount to be transferred exceeds the allowance.
                    if gt(amount, allowance_) {
                        mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
                        revert(0x1c, 0x04)
                    }
                    // Subtract and store the updated allowance.
                    sstore(allowanceSlot, sub(allowance_, amount))
                }
                // Compute the balance slot and load its value.
                mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
                let fromBalanceSlot := keccak256(0x0c, 0x20)
                let fromBalance := sload(fromBalanceSlot)
                // Revert if insufficient balance.
                if gt(amount, fromBalance) {
                    mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated balance.
                sstore(fromBalanceSlot, sub(fromBalance, amount))
                // Compute the balance slot of `to`.
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x20)
                // Add and store the updated balance of `to`.
                // Will not overflow because the sum of all user balances
                // cannot exceed the maximum uint256 value.
                sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
                // Emit the {Transfer} event.
                mstore(0x20, amount)
                log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
            }
            _afterTokenTransfer(from, to, amount);
            return true;
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          EIP-2612                          */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev For more performance, override to return the constant value
        /// of `keccak256(bytes(name()))` if `name()` will never change.
        function _constantNameHash() internal view virtual returns (bytes32 result) {}
        /// @dev Returns the current nonce for `owner`.
        /// This value is used to compute the signature for EIP-2612 permit.
        function nonces(address owner) public view virtual returns (uint256 result) {
            /// @solidity memory-safe-assembly
            assembly {
                // Compute the nonce slot and load its value.
                mstore(0x0c, _NONCES_SLOT_SEED)
                mstore(0x00, owner)
                result := sload(keccak256(0x0c, 0x20))
            }
        }
        /// @dev Sets `value` as the allowance of `spender` over the tokens of `owner`,
        /// authorized by a signed approval by `owner`.
        ///
        /// Emits a {Approval} event.
        function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) public virtual {
            bytes32 nameHash = _constantNameHash();
            //  We simply calculate it on-the-fly to allow for cases where the `name` may change.
            if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
            /// @solidity memory-safe-assembly
            assembly {
                // Revert if the block timestamp is greater than `deadline`.
                if gt(timestamp(), deadline) {
                    mstore(0x00, 0x1a15a3cc) // `PermitExpired()`.
                    revert(0x1c, 0x04)
                }
                let m := mload(0x40) // Grab the free memory pointer.
                // Clean the upper 96 bits.
                owner := shr(96, shl(96, owner))
                spender := shr(96, shl(96, spender))
                // Compute the nonce slot and load its value.
                mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
                mstore(0x00, owner)
                let nonceSlot := keccak256(0x0c, 0x20)
                let nonceValue := sload(nonceSlot)
                // Prepare the domain separator.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), nameHash)
                mstore(add(m, 0x40), _VERSION_HASH)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())
                mstore(0x2e, keccak256(m, 0xa0))
                // Prepare the struct hash.
                mstore(m, _PERMIT_TYPEHASH)
                mstore(add(m, 0x20), owner)
                mstore(add(m, 0x40), spender)
                mstore(add(m, 0x60), value)
                mstore(add(m, 0x80), nonceValue)
                mstore(add(m, 0xa0), deadline)
                mstore(0x4e, keccak256(m, 0xc0))
                // Prepare the ecrecover calldata.
                mstore(0x00, keccak256(0x2c, 0x42))
                mstore(0x20, and(0xff, v))
                mstore(0x40, r)
                mstore(0x60, s)
                let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
                // If the ecrecover fails, the returndatasize will be 0x00,
                // `owner` will be checked if it equals the hash at 0x00,
                // which evaluates to false (i.e. 0), and we will revert.
                // If the ecrecover succeeds, the returndatasize will be 0x20,
                // `owner` will be compared against the returned address at 0x20.
                if iszero(eq(mload(returndatasize()), owner)) {
                    mstore(0x00, 0xddafbaef) // `InvalidPermit()`.
                    revert(0x1c, 0x04)
                }
                // Increment and store the updated nonce.
                sstore(nonceSlot, add(nonceValue, t)) // `t` is 1 if ecrecover succeeds.
                // Compute the allowance slot and store the value.
                // The `owner` is already at slot 0x20.
                mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
                sstore(keccak256(0x2c, 0x34), value)
                // Emit the {Approval} event.
                log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
                mstore(0x40, m) // Restore the free memory pointer.
                mstore(0x60, 0) // Restore the zero pointer.
            }
        }
        /// @dev Returns the EIP-712 domain separator for the EIP-2612 permit.
        function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
            bytes32 nameHash = _constantNameHash();
            //  We simply calculate it on-the-fly to allow for cases where the `name` may change.
            if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
            /// @solidity memory-safe-assembly
            assembly {
                let m := mload(0x40) // Grab the free memory pointer.
                mstore(m, _DOMAIN_TYPEHASH)
                mstore(add(m, 0x20), nameHash)
                mstore(add(m, 0x40), _VERSION_HASH)
                mstore(add(m, 0x60), chainid())
                mstore(add(m, 0x80), address())
                result := keccak256(m, 0xa0)
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                  INTERNAL MINT FUNCTIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Mints `amount` tokens to `to`, increasing the total supply.
        ///
        /// Emits a {Transfer} event.
        function _mint(address to, uint256 amount) internal virtual {
            _beforeTokenTransfer(address(0), to, amount);
            /// @solidity memory-safe-assembly
            assembly {
                let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
                let totalSupplyAfter := add(totalSupplyBefore, amount)
                // Revert if the total supply overflows.
                if lt(totalSupplyAfter, totalSupplyBefore) {
                    mstore(0x00, 0xe5cfe957) // `TotalSupplyOverflow()`.
                    revert(0x1c, 0x04)
                }
                // Store the updated total supply.
                sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
                // Compute the balance slot and load its value.
                mstore(0x0c, _BALANCE_SLOT_SEED)
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x20)
                // Add and store the updated balance.
                sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
                // Emit the {Transfer} event.
                mstore(0x20, amount)
                log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
            }
            _afterTokenTransfer(address(0), to, amount);
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                  INTERNAL BURN FUNCTIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Burns `amount` tokens from `from`, reducing the total supply.
        ///
        /// Emits a {Transfer} event.
        function _burn(address from, uint256 amount) internal virtual {
            _beforeTokenTransfer(from, address(0), amount);
            /// @solidity memory-safe-assembly
            assembly {
                // Compute the balance slot and load its value.
                mstore(0x0c, _BALANCE_SLOT_SEED)
                mstore(0x00, from)
                let fromBalanceSlot := keccak256(0x0c, 0x20)
                let fromBalance := sload(fromBalanceSlot)
                // Revert if insufficient balance.
                if gt(amount, fromBalance) {
                    mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated balance.
                sstore(fromBalanceSlot, sub(fromBalance, amount))
                // Subtract and store the updated total supply.
                sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
                // Emit the {Transfer} event.
                mstore(0x00, amount)
                log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
            }
            _afterTokenTransfer(from, address(0), amount);
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                INTERNAL TRANSFER FUNCTIONS                 */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Moves `amount` of tokens from `from` to `to`.
        function _transfer(address from, address to, uint256 amount) internal virtual {
            _beforeTokenTransfer(from, to, amount);
            /// @solidity memory-safe-assembly
            assembly {
                let from_ := shl(96, from)
                // Compute the balance slot and load its value.
                mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
                let fromBalanceSlot := keccak256(0x0c, 0x20)
                let fromBalance := sload(fromBalanceSlot)
                // Revert if insufficient balance.
                if gt(amount, fromBalance) {
                    mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                    revert(0x1c, 0x04)
                }
                // Subtract and store the updated balance.
                sstore(fromBalanceSlot, sub(fromBalance, amount))
                // Compute the balance slot of `to`.
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x20)
                // Add and store the updated balance of `to`.
                // Will not overflow because the sum of all user balances
                // cannot exceed the maximum uint256 value.
                sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
                // Emit the {Transfer} event.
                mstore(0x20, amount)
                log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
            }
            _afterTokenTransfer(from, to, amount);
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                INTERNAL ALLOWANCE FUNCTIONS                */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Updates the allowance of `owner` for `spender` based on spent `amount`.
        function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
            /// @solidity memory-safe-assembly
            assembly {
                // Compute the allowance slot and load its value.
                mstore(0x20, spender)
                mstore(0x0c, _ALLOWANCE_SLOT_SEED)
                mstore(0x00, owner)
                let allowanceSlot := keccak256(0x0c, 0x34)
                let allowance_ := sload(allowanceSlot)
                // If the allowance is not the maximum uint256 value.
                if add(allowance_, 1) {
                    // Revert if the amount to be transferred exceeds the allowance.
                    if gt(amount, allowance_) {
                        mstore(0x00, 0x13be252b) // `InsufficientAllowance()`.
                        revert(0x1c, 0x04)
                    }
                    // Subtract and store the updated allowance.
                    sstore(allowanceSlot, sub(allowance_, amount))
                }
            }
        }
        /// @dev Sets `amount` as the allowance of `spender` over the tokens of `owner`.
        ///
        /// Emits a {Approval} event.
        function _approve(address owner, address spender, uint256 amount) internal virtual {
            /// @solidity memory-safe-assembly
            assembly {
                let owner_ := shl(96, owner)
                // Compute the allowance slot and store the amount.
                mstore(0x20, spender)
                mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
                sstore(keccak256(0x0c, 0x34), amount)
                // Emit the {Approval} event.
                mstore(0x00, amount)
                log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
            }
        }
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                     HOOKS TO OVERRIDE                      */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
        /// @dev Hook that is called before any transfer of tokens.
        /// This includes minting and burning.
        function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
        /// @dev Hook that is called after any transfer of tokens.
        /// This includes minting and burning.
        function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.19;
    // Common.sol
    //
    // Common mathematical functions needed by both SD59x18 and UD60x18. Note that these global functions do not
    // always operate with SD59x18 and UD60x18 numbers.
    /*//////////////////////////////////////////////////////////////////////////
                                    CUSTOM ERRORS
    //////////////////////////////////////////////////////////////////////////*/
    /// @notice Thrown when the resultant value in {mulDiv} overflows uint256.
    error PRBMath_MulDiv_Overflow(uint256 x, uint256 y, uint256 denominator);
    /// @notice Thrown when the resultant value in {mulDiv18} overflows uint256.
    error PRBMath_MulDiv18_Overflow(uint256 x, uint256 y);
    /// @notice Thrown when one of the inputs passed to {mulDivSigned} is `type(int256).min`.
    error PRBMath_MulDivSigned_InputTooSmall();
    /// @notice Thrown when the resultant value in {mulDivSigned} overflows int256.
    error PRBMath_MulDivSigned_Overflow(int256 x, int256 y);
    /*//////////////////////////////////////////////////////////////////////////
                                        CONSTANTS
    //////////////////////////////////////////////////////////////////////////*/
    /// @dev The maximum value a uint128 number can have.
    uint128 constant MAX_UINT128 = type(uint128).max;
    /// @dev The maximum value a uint40 number can have.
    uint40 constant MAX_UINT40 = type(uint40).max;
    /// @dev The unit number, which the decimal precision of the fixed-point types.
    uint256 constant UNIT = 1e18;
    /// @dev The unit number inverted mod 2^256.
    uint256 constant UNIT_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281;
    /// @dev The the largest power of two that divides the decimal value of `UNIT`. The logarithm of this value is the least significant
    /// bit in the binary representation of `UNIT`.
    uint256 constant UNIT_LPOTD = 262144;
    /*//////////////////////////////////////////////////////////////////////////
                                        FUNCTIONS
    //////////////////////////////////////////////////////////////////////////*/
    /// @notice Calculates the binary exponent of x using the binary fraction method.
    /// @dev Has to use 192.64-bit fixed-point numbers. See https://ethereum.stackexchange.com/a/96594/24693.
    /// @param x The exponent as an unsigned 192.64-bit fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    /// @custom:smtchecker abstract-function-nondet
    function exp2(uint256 x) pure returns (uint256 result) {
        unchecked {
            // Start from 0.5 in the 192.64-bit fixed-point format.
            result = 0x800000000000000000000000000000000000000000000000;
            // The following logic multiplies the result by $\\sqrt{2^{-i}}$ when the bit at position i is 1. Key points:
            //
            // 1. Intermediate results will not overflow, as the starting point is 2^191 and all magic factors are under 2^65.
            // 2. The rationale for organizing the if statements into groups of 8 is gas savings. If the result of performing
            // a bitwise AND operation between x and any value in the array [0x80; 0x40; 0x20; 0x10; 0x08; 0x04; 0x02; 0x01] is 1,
            // we know that `x & 0xFF` is also 1.
            if (x & 0xFF00000000000000 > 0) {
                if (x & 0x8000000000000000 > 0) {
                    result = (result * 0x16A09E667F3BCC909) >> 64;
                }
                if (x & 0x4000000000000000 > 0) {
                    result = (result * 0x1306FE0A31B7152DF) >> 64;
                }
                if (x & 0x2000000000000000 > 0) {
                    result = (result * 0x1172B83C7D517ADCE) >> 64;
                }
                if (x & 0x1000000000000000 > 0) {
                    result = (result * 0x10B5586CF9890F62A) >> 64;
                }
                if (x & 0x800000000000000 > 0) {
                    result = (result * 0x1059B0D31585743AE) >> 64;
                }
                if (x & 0x400000000000000 > 0) {
                    result = (result * 0x102C9A3E778060EE7) >> 64;
                }
                if (x & 0x200000000000000 > 0) {
                    result = (result * 0x10163DA9FB33356D8) >> 64;
                }
                if (x & 0x100000000000000 > 0) {
                    result = (result * 0x100B1AFA5ABCBED61) >> 64;
                }
            }
            if (x & 0xFF000000000000 > 0) {
                if (x & 0x80000000000000 > 0) {
                    result = (result * 0x10058C86DA1C09EA2) >> 64;
                }
                if (x & 0x40000000000000 > 0) {
                    result = (result * 0x1002C605E2E8CEC50) >> 64;
                }
                if (x & 0x20000000000000 > 0) {
                    result = (result * 0x100162F3904051FA1) >> 64;
                }
                if (x & 0x10000000000000 > 0) {
                    result = (result * 0x1000B175EFFDC76BA) >> 64;
                }
                if (x & 0x8000000000000 > 0) {
                    result = (result * 0x100058BA01FB9F96D) >> 64;
                }
                if (x & 0x4000000000000 > 0) {
                    result = (result * 0x10002C5CC37DA9492) >> 64;
                }
                if (x & 0x2000000000000 > 0) {
                    result = (result * 0x1000162E525EE0547) >> 64;
                }
                if (x & 0x1000000000000 > 0) {
                    result = (result * 0x10000B17255775C04) >> 64;
                }
            }
            if (x & 0xFF0000000000 > 0) {
                if (x & 0x800000000000 > 0) {
                    result = (result * 0x1000058B91B5BC9AE) >> 64;
                }
                if (x & 0x400000000000 > 0) {
                    result = (result * 0x100002C5C89D5EC6D) >> 64;
                }
                if (x & 0x200000000000 > 0) {
                    result = (result * 0x10000162E43F4F831) >> 64;
                }
                if (x & 0x100000000000 > 0) {
                    result = (result * 0x100000B1721BCFC9A) >> 64;
                }
                if (x & 0x80000000000 > 0) {
                    result = (result * 0x10000058B90CF1E6E) >> 64;
                }
                if (x & 0x40000000000 > 0) {
                    result = (result * 0x1000002C5C863B73F) >> 64;
                }
                if (x & 0x20000000000 > 0) {
                    result = (result * 0x100000162E430E5A2) >> 64;
                }
                if (x & 0x10000000000 > 0) {
                    result = (result * 0x1000000B172183551) >> 64;
                }
            }
            if (x & 0xFF00000000 > 0) {
                if (x & 0x8000000000 > 0) {
                    result = (result * 0x100000058B90C0B49) >> 64;
                }
                if (x & 0x4000000000 > 0) {
                    result = (result * 0x10000002C5C8601CC) >> 64;
                }
                if (x & 0x2000000000 > 0) {
                    result = (result * 0x1000000162E42FFF0) >> 64;
                }
                if (x & 0x1000000000 > 0) {
                    result = (result * 0x10000000B17217FBB) >> 64;
                }
                if (x & 0x800000000 > 0) {
                    result = (result * 0x1000000058B90BFCE) >> 64;
                }
                if (x & 0x400000000 > 0) {
                    result = (result * 0x100000002C5C85FE3) >> 64;
                }
                if (x & 0x200000000 > 0) {
                    result = (result * 0x10000000162E42FF1) >> 64;
                }
                if (x & 0x100000000 > 0) {
                    result = (result * 0x100000000B17217F8) >> 64;
                }
            }
            if (x & 0xFF000000 > 0) {
                if (x & 0x80000000 > 0) {
                    result = (result * 0x10000000058B90BFC) >> 64;
                }
                if (x & 0x40000000 > 0) {
                    result = (result * 0x1000000002C5C85FE) >> 64;
                }
                if (x & 0x20000000 > 0) {
                    result = (result * 0x100000000162E42FF) >> 64;
                }
                if (x & 0x10000000 > 0) {
                    result = (result * 0x1000000000B17217F) >> 64;
                }
                if (x & 0x8000000 > 0) {
                    result = (result * 0x100000000058B90C0) >> 64;
                }
                if (x & 0x4000000 > 0) {
                    result = (result * 0x10000000002C5C860) >> 64;
                }
                if (x & 0x2000000 > 0) {
                    result = (result * 0x1000000000162E430) >> 64;
                }
                if (x & 0x1000000 > 0) {
                    result = (result * 0x10000000000B17218) >> 64;
                }
            }
            if (x & 0xFF0000 > 0) {
                if (x & 0x800000 > 0) {
                    result = (result * 0x1000000000058B90C) >> 64;
                }
                if (x & 0x400000 > 0) {
                    result = (result * 0x100000000002C5C86) >> 64;
                }
                if (x & 0x200000 > 0) {
                    result = (result * 0x10000000000162E43) >> 64;
                }
                if (x & 0x100000 > 0) {
                    result = (result * 0x100000000000B1721) >> 64;
                }
                if (x & 0x80000 > 0) {
                    result = (result * 0x10000000000058B91) >> 64;
                }
                if (x & 0x40000 > 0) {
                    result = (result * 0x1000000000002C5C8) >> 64;
                }
                if (x & 0x20000 > 0) {
                    result = (result * 0x100000000000162E4) >> 64;
                }
                if (x & 0x10000 > 0) {
                    result = (result * 0x1000000000000B172) >> 64;
                }
            }
            if (x & 0xFF00 > 0) {
                if (x & 0x8000 > 0) {
                    result = (result * 0x100000000000058B9) >> 64;
                }
                if (x & 0x4000 > 0) {
                    result = (result * 0x10000000000002C5D) >> 64;
                }
                if (x & 0x2000 > 0) {
                    result = (result * 0x1000000000000162E) >> 64;
                }
                if (x & 0x1000 > 0) {
                    result = (result * 0x10000000000000B17) >> 64;
                }
                if (x & 0x800 > 0) {
                    result = (result * 0x1000000000000058C) >> 64;
                }
                if (x & 0x400 > 0) {
                    result = (result * 0x100000000000002C6) >> 64;
                }
                if (x & 0x200 > 0) {
                    result = (result * 0x10000000000000163) >> 64;
                }
                if (x & 0x100 > 0) {
                    result = (result * 0x100000000000000B1) >> 64;
                }
            }
            if (x & 0xFF > 0) {
                if (x & 0x80 > 0) {
                    result = (result * 0x10000000000000059) >> 64;
                }
                if (x & 0x40 > 0) {
                    result = (result * 0x1000000000000002C) >> 64;
                }
                if (x & 0x20 > 0) {
                    result = (result * 0x10000000000000016) >> 64;
                }
                if (x & 0x10 > 0) {
                    result = (result * 0x1000000000000000B) >> 64;
                }
                if (x & 0x8 > 0) {
                    result = (result * 0x10000000000000006) >> 64;
                }
                if (x & 0x4 > 0) {
                    result = (result * 0x10000000000000003) >> 64;
                }
                if (x & 0x2 > 0) {
                    result = (result * 0x10000000000000001) >> 64;
                }
                if (x & 0x1 > 0) {
                    result = (result * 0x10000000000000001) >> 64;
                }
            }
            // In the code snippet below, two operations are executed simultaneously:
            //
            // 1. The result is multiplied by $(2^n + 1)$, where $2^n$ represents the integer part, and the additional 1
            // accounts for the initial guess of 0.5. This is achieved by subtracting from 191 instead of 192.
            // 2. The result is then converted to an unsigned 60.18-decimal fixed-point format.
            //
            // The underlying logic is based on the relationship $2^{191-ip} = 2^{ip} / 2^{191}$, where $ip$ denotes the,
            // integer part, $2^n$.
            result *= UNIT;
            result >>= (191 - (x >> 64));
        }
    }
    /// @notice Finds the zero-based index of the first 1 in the binary representation of x.
    ///
    /// @dev See the note on "msb" in this Wikipedia article: https://en.wikipedia.org/wiki/Find_first_set
    ///
    /// Each step in this implementation is equivalent to this high-level code:
    ///
    /// ```solidity
    /// if (x >= 2 ** 128) {
    ///     x >>= 128;
    ///     result += 128;
    /// }
    /// ```
    ///
    /// Where 128 is replaced with each respective power of two factor. See the full high-level implementation here:
    /// https://gist.github.com/PaulRBerg/f932f8693f2733e30c4d479e8e980948
    ///
    /// The Yul instructions used below are:
    ///
    /// - "gt" is "greater than"
    /// - "or" is the OR bitwise operator
    /// - "shl" is "shift left"
    /// - "shr" is "shift right"
    ///
    /// @param x The uint256 number for which to find the index of the most significant bit.
    /// @return result The index of the most significant bit as a uint256.
    /// @custom:smtchecker abstract-function-nondet
    function msb(uint256 x) pure returns (uint256 result) {
        // 2^128
        assembly ("memory-safe") {
            let factor := shl(7, gt(x, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^64
        assembly ("memory-safe") {
            let factor := shl(6, gt(x, 0xFFFFFFFFFFFFFFFF))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^32
        assembly ("memory-safe") {
            let factor := shl(5, gt(x, 0xFFFFFFFF))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^16
        assembly ("memory-safe") {
            let factor := shl(4, gt(x, 0xFFFF))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^8
        assembly ("memory-safe") {
            let factor := shl(3, gt(x, 0xFF))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^4
        assembly ("memory-safe") {
            let factor := shl(2, gt(x, 0xF))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^2
        assembly ("memory-safe") {
            let factor := shl(1, gt(x, 0x3))
            x := shr(factor, x)
            result := or(result, factor)
        }
        // 2^1
        // No need to shift x any more.
        assembly ("memory-safe") {
            let factor := gt(x, 0x1)
            result := or(result, factor)
        }
    }
    /// @notice Calculates x*y÷denominator with 512-bit precision.
    ///
    /// @dev Credits to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv.
    ///
    /// Notes:
    /// - The result is rounded toward zero.
    ///
    /// Requirements:
    /// - The denominator must not be zero.
    /// - The result must fit in uint256.
    ///
    /// @param x The multiplicand as a uint256.
    /// @param y The multiplier as a uint256.
    /// @param denominator The divisor as a uint256.
    /// @return result The result as a uint256.
    /// @custom:smtchecker abstract-function-nondet
    function mulDiv(uint256 x, uint256 y, uint256 denominator) pure returns (uint256 result) {
        // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
        // use the Chinese Remainder Theorem to reconstruct the 512-bit result. The result is stored in two 256
        // variables such that product = prod1 * 2^256 + prod0.
        uint256 prod0; // Least significant 256 bits of the product
        uint256 prod1; // Most significant 256 bits of the product
        assembly ("memory-safe") {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }
        // Handle non-overflow cases, 256 by 256 division.
        if (prod1 == 0) {
            unchecked {
                return prod0 / denominator;
            }
        }
        // Make sure the result is less than 2^256. Also prevents denominator == 0.
        if (prod1 >= denominator) {
            revert PRBMath_MulDiv_Overflow(x, y, denominator);
        }
        ////////////////////////////////////////////////////////////////////////////
        // 512 by 256 division
        ////////////////////////////////////////////////////////////////////////////
        // Make division exact by subtracting the remainder from [prod1 prod0].
        uint256 remainder;
        assembly ("memory-safe") {
            // Compute remainder using the mulmod Yul instruction.
            remainder := mulmod(x, y, denominator)
            // Subtract 256 bit number from 512-bit number.
            prod1 := sub(prod1, gt(remainder, prod0))
            prod0 := sub(prod0, remainder)
        }
        unchecked {
            // Calculate the largest power of two divisor of the denominator using the unary operator ~. This operation cannot overflow
            // because the denominator cannot be zero at this point in the function execution. The result is always >= 1.
            // For more detail, see https://cs.stackexchange.com/q/138556/92363.
            uint256 lpotdod = denominator & (~denominator + 1);
            uint256 flippedLpotdod;
            assembly ("memory-safe") {
                // Factor powers of two out of denominator.
                denominator := div(denominator, lpotdod)
                // Divide [prod1 prod0] by lpotdod.
                prod0 := div(prod0, lpotdod)
                // Get the flipped value `2^256 / lpotdod`. If the `lpotdod` is zero, the flipped value is one.
                // `sub(0, lpotdod)` produces the two's complement version of `lpotdod`, which is equivalent to flipping all the bits.
                // However, `div` interprets this value as an unsigned value: https://ethereum.stackexchange.com/q/147168/24693
                flippedLpotdod := add(div(sub(0, lpotdod), lpotdod), 1)
            }
            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * flippedLpotdod;
            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;
            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256
            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
        }
    }
    /// @notice Calculates x*y÷1e18 with 512-bit precision.
    ///
    /// @dev A variant of {mulDiv} with constant folding, i.e. in which the denominator is hard coded to 1e18.
    ///
    /// Notes:
    /// - The body is purposely left uncommented; to understand how this works, see the documentation in {mulDiv}.
    /// - The result is rounded toward zero.
    /// - We take as an axiom that the result cannot be `MAX_UINT256` when x and y solve the following system of equations:
    ///
    /// $$
    /// \\begin{cases}
    ///     x * y = MAX\\_UINT256 * UNIT \\\\
    ///     (x * y) \\% UNIT \\geq \\frac{UNIT}{2}
    /// \\end{cases}
    /// $$
    ///
    /// Requirements:
    /// - Refer to the requirements in {mulDiv}.
    /// - The result must fit in uint256.
    ///
    /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number.
    /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number.
    /// @return result The result as an unsigned 60.18-decimal fixed-point number.
    /// @custom:smtchecker abstract-function-nondet
    function mulDiv18(uint256 x, uint256 y) pure returns (uint256 result) {
        uint256 prod0;
        uint256 prod1;
        assembly ("memory-safe") {
            let mm := mulmod(x, y, not(0))
            prod0 := mul(x, y)
            prod1 := sub(sub(mm, prod0), lt(mm, prod0))
        }
        if (prod1 == 0) {
            unchecked {
                return prod0 / UNIT;
            }
        }
        if (prod1 >= UNIT) {
            revert PRBMath_MulDiv18_Overflow(x, y);
        }
        uint256 remainder;
        assembly ("memory-safe") {
            remainder := mulmod(x, y, UNIT)
            result :=
                mul(
                    or(
                        div(sub(prod0, remainder), UNIT_LPOTD),
                        mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, UNIT_LPOTD), UNIT_LPOTD), 1))
                    ),
                    UNIT_INVERSE
                )
        }
    }
    /// @notice Calculates x*y÷denominator with 512-bit precision.
    ///
    /// @dev This is an extension of {mulDiv} for signed numbers, which works by computing the signs and the absolute values separately.
    ///
    /// Notes:
    /// - The result is rounded toward zero.
    ///
    /// Requirements:
    /// - Refer to the requirements in {mulDiv}.
    /// - None of the inputs can be `type(int256).min`.
    /// - The result must fit in int256.
    ///
    /// @param x The multiplicand as an int256.
    /// @param y The multiplier as an int256.
    /// @param denominator The divisor as an int256.
    /// @return result The result as an int256.
    /// @custom:smtchecker abstract-function-nondet
    function mulDivSigned(int256 x, int256 y, int256 denominator) pure returns (int256 result) {
        if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) {
            revert PRBMath_MulDivSigned_InputTooSmall();
        }
        // Get hold of the absolute values of x, y and the denominator.
        uint256 xAbs;
        uint256 yAbs;
        uint256 dAbs;
        unchecked {
            xAbs = x < 0 ? uint256(-x) : uint256(x);
            yAbs = y < 0 ? uint256(-y) : uint256(y);
            dAbs = denominator < 0 ? uint256(-denominator) : uint256(denominator);
        }
        // Compute the absolute value of x*y÷denominator. The result must fit in int256.
        uint256 resultAbs = mulDiv(xAbs, yAbs, dAbs);
        if (resultAbs > uint256(type(int256).max)) {
            revert PRBMath_MulDivSigned_Overflow(x, y);
        }
        // Get the signs of x, y and the denominator.
        uint256 sx;
        uint256 sy;
        uint256 sd;
        assembly ("memory-safe") {
            // "sgt" is the "signed greater than" assembly instruction and "sub(0,1)" is -1 in two's complement.
            sx := sgt(x, sub(0, 1))
            sy := sgt(y, sub(0, 1))
            sd := sgt(denominator, sub(0, 1))
        }
        // XOR over sx, sy and sd. What this does is to check whether there are 1 or 3 negative signs in the inputs.
        // If there are, the result should be negative. Otherwise, it should be positive.
        unchecked {
            result = sx ^ sy ^ sd == 0 ? -int256(resultAbs) : int256(resultAbs);
        }
    }
    /// @notice Calculates the square root of x using the Babylonian method.
    ///
    /// @dev See https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method.
    ///
    /// Notes:
    /// - If x is not a perfect square, the result is rounded down.
    /// - Credits to OpenZeppelin for the explanations in comments below.
    ///
    /// @param x The uint256 number for which to calculate the square root.
    /// @return result The result as a uint256.
    /// @custom:smtchecker abstract-function-nondet
    function sqrt(uint256 x) pure returns (uint256 result) {
        if (x == 0) {
            return 0;
        }
        // For our first guess, we calculate the biggest power of 2 which is smaller than the square root of x.
        //
        // We know that the "msb" (most significant bit) of x is a power of 2 such that we have:
        //
        // $$
        // msb(x) <= x <= 2*msb(x)$
        // $$
        //
        // We write $msb(x)$ as $2^k$, and we get:
        //
        // $$
        // k = log_2(x)
        // $$
        //
        // Thus, we can write the initial inequality as:
        //
        // $$
        // 2^{log_2(x)} <= x <= 2*2^{log_2(x)+1} \\\\
        // sqrt(2^k) <= sqrt(x) < sqrt(2^{k+1}) \\\\
        // 2^{k/2} <= sqrt(x) < 2^{(k+1)/2} <= 2^{(k/2)+1}
        // $$
        //
        // Consequently, $2^{log_2(x) /2} is a good first approximation of sqrt(x) with at least one correct bit.
        uint256 xAux = uint256(x);
        result = 1;
        if (xAux >= 2 ** 128) {
            xAux >>= 128;
            result <<= 64;
        }
        if (xAux >= 2 ** 64) {
            xAux >>= 64;
            result <<= 32;
        }
        if (xAux >= 2 ** 32) {
            xAux >>= 32;
            result <<= 16;
        }
        if (xAux >= 2 ** 16) {
            xAux >>= 16;
            result <<= 8;
        }
        if (xAux >= 2 ** 8) {
            xAux >>= 8;
            result <<= 4;
        }
        if (xAux >= 2 ** 4) {
            xAux >>= 4;
            result <<= 2;
        }
        if (xAux >= 2 ** 2) {
            result <<= 1;
        }
        // At this point, `result` is an estimation with at least one bit of precision. We know the true value has at
        // most 128 bits, since it is the square root of a uint256. Newton's method converges quadratically (precision
        // doubles at every iteration). We thus need at most 7 iteration to turn our partial result with one bit of
        // precision into the expected uint128 result.
        unchecked {
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            result = (result + x / result) >> 1;
            // If x is not a perfect square, round the result toward zero.
            uint256 roundedResult = x / result;
            if (result >= roundedResult) {
                result = roundedResult;
            }
        }
    }
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity 0.8.22;
    library NumberUtils {
        function addCheckOverflow(uint256 a, uint256 b) internal pure returns (bool) {
            uint256 c = 0;
            unchecked {
                c = a + b;
            }
            return c < a || c < b;
        }
        function mulCheckOverflow(uint256 a, uint256 b) internal pure returns (bool) {
            if (a == 0 || b == 0) {
                return false;
            }
            uint256 c;
            unchecked {
                c = a * b;
            }
            return c / a != b;
        }
        function mulDivCheckOverflow(uint256 a, uint256 b, uint256 denominator) internal pure returns (bool) {
            // Taken from prb - math
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly ("memory-safe") {
                let mm := mulmod(a, b, not(0))
                prod0 := mul(a, b)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }
            return prod1 >= denominator;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol)
    pragma solidity ^0.8.20;
    import {Initializable} from "../proxy/utils/Initializable.sol";
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract ContextUpgradeable is Initializable {
        function __Context_init() internal onlyInitializing {
        }
        function __Context_init_unchained() internal onlyInitializing {
        }
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
    pragma solidity ^0.8.20;
    import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
    import {Initializable} from "../../proxy/utils/Initializable.sol";
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
     * for the additional interface id that will be supported. For example:
     *
     * ```solidity
     * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
     *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
     * }
     * ```
     */
    abstract contract ERC165Upgradeable is Initializable, IERC165 {
        function __ERC165_init() internal onlyInitializing {
        }
        function __ERC165_init_unchained() internal onlyInitializing {
        }
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.20;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }