{"file_path":"src/projects/jmi/JMIExtension.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\nimport { IERC20Metadata as IERC20 } from \"../../../lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\n\nimport { SafeERC20 } from \"../../../lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport { UIntMath } from \"../../../lib/common/src/libs/UIntMath.sol\";\n\nimport { Pausable } from \"../../components/pausable/Pausable.sol\";\n\nimport { IMTokenLike } from \"../../interfaces/IMTokenLike.sol\";\nimport { ISwapFacility } from \"../../swap/interfaces/ISwapFacility.sol\";\n\nimport { IMYieldToOne } from \"../yieldToOne/interfaces/IMYieldToOne.sol\";\nimport { MYieldToOne } from \"../yieldToOne/MYieldToOne.sol\";\n\nimport { IJMIExtension } from \"./IJMIExtension.sol\";\n\n/**\n\n     ██╗██╗   ██╗███████╗████████╗    ███╗   ███╗██╗███╗   ██╗████████╗    ██╗████████╗\n     ██║██║   ██║██╔════╝╚══██╔══╝    ████╗ ████║██║████╗  ██║╚══██╔══╝    ██║╚══██╔══╝\n     ██║██║   ██║███████╗   ██║       ██╔████╔██║██║██╔██╗ ██║   ██║       ██║   ██║\n██   ██║██║   ██║╚════██║   ██║       ██║╚██╔╝██║██║██║╚██╗██║   ██║       ██║   ██║\n╚█████╔╝╚██████╔╝███████║   ██║       ██║ ╚═╝ ██║██║██║ ╚████║   ██║       ██║   ██║\n ╚════╝  ╚═════╝ ╚══════╝   ╚═╝       ╚═╝     ╚═╝╚═╝╚═╝  ╚═══╝   ╚═╝       ╚═╝   ╚═╝\n\n*/\n\nabstract contract JMIExtensionLayout {\n    struct Asset {\n        // Cap amount for the asset, formatted in the asset's decimals (i.e. 18 decimals for DAI).\n        // Primary asset (M) is implicit and has no cap.\n        uint256 cap;\n        // Balance of the asset backing the extension token.\n        // Casted to uint240 to fit in a single storage slot with `decimals`.\n        // Aligns with M supply which can't exceed uint240.\n        uint240 balance;\n        // Decimals of the asset.\n        uint8 decimals;\n    }\n\n    struct JMIExtensionStorageStruct {\n        // All supported collateral assets and their properties.\n        // If an asset is not present in the mapping or has a cap of 0, it is not allowed.\n        mapping(address asset => Asset) assets;\n        // Total amount of non M assets backing the extension token, formatted in extension decimals (i.e. 6 decimals).\n        uint256 totalAssets;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.JMIExtension\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _JMI_EXTENSION_STORAGE_LOCATION =\n        0x4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b00;\n\n    function _getJMIExtensionStorageLocation() internal pure returns (JMIExtensionStorageStruct storage $) {\n        assembly {\n            $.slot := _JMI_EXTENSION_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title  JMIExtension\n * @notice Upgradeable ERC20 Token contract for wrapping M into a non-rebasing token\n *         with yield claimable by a single recipient and JMI (Just Mint It) backing model.\n *         The JMI backing model allows users to mint the extension token\n *         by depositing either M or an allowed asset token.\n *         It assumes that both tokens are pegged 1:1.\n *         Fee on transfer tokens are not supported.\n * @author M0 Labs\n */\ncontract JMIExtension is IJMIExtension, JMIExtensionLayout, MYieldToOne {\n    using SafeERC20 for IERC20;\n\n    /* ============ Variables ============ */\n\n    /// @inheritdoc IJMIExtension\n    bytes32 public constant ASSET_CAP_MANAGER_ROLE = keccak256(\"ASSET_CAP_MANAGER_ROLE\");\n\n    /// @inheritdoc IJMIExtension\n    uint8 public constant M_DECIMALS = 6;\n\n    /* ============ Constructor ============ */\n\n    /**\n     * @custom:oz-upgrades-unsafe-allow constructor\n     * @notice Constructs JMIExtension Implementation contract\n     * @dev    Sets immutable storage.\n     * @param  mToken       The address of $M token.\n     * @param  swapFacility The address of Swap Facility.\n     */\n    constructor(address mToken, address swapFacility) MYieldToOne(mToken, swapFacility) {}\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @dev   Initializes the M extension token with JMI backing model and yield claimable by a single recipient.\n     * @param name                  The name of the token (e.g. \"Just Mint It\").\n     * @param symbol                The symbol of the token (e.g. \"JMI\").\n     * @param yieldRecipient        The address of a yield recipient.\n     * @param admin                 The address of an admin.\n     * @param assetCapManager       The address of an asset cap manager.\n     * @param freezeManager         The address of a freeze manager.\n     * @param pauser                The address of a pauser.\n     * @param yieldRecipientManager The address of a yield recipient manager.\n     */\n    function initialize(\n        string memory name,\n        string memory symbol,\n        address yieldRecipient,\n        address admin,\n        address assetCapManager,\n        address freezeManager,\n        address pauser,\n        address yieldRecipientManager\n    ) public virtual initializer {\n        __JMIExtension_init(\n            name,\n            symbol,\n            yieldRecipient,\n            admin,\n            assetCapManager,\n            freezeManager,\n            pauser,\n            yieldRecipientManager\n        );\n    }\n\n    /**\n     * @dev   Initializes the JMIExtension token.\n     * @param name                  The name of the token (e.g. \"Just Mint It\").\n     * @param symbol                The symbol of the token (e.g. \"JMI\").\n     * @param yieldRecipient        The address of a yield destination.\n     * @param admin                 The address of an admin.\n     * @param assetCapManager       The address of an asset cap manager.\n     * @param freezeManager         The address of a freeze manager.\n     * @param pauser                The address of a pauser.\n     * @param yieldRecipientManager The address of a yield recipient setter.\n     */\n    function __JMIExtension_init(\n        string memory name,\n        string memory symbol,\n        address yieldRecipient,\n        address admin,\n        address assetCapManager,\n        address freezeManager,\n        address pauser,\n        address yieldRecipientManager\n    ) internal onlyInitializing {\n        if (assetCapManager == address(0)) revert ZeroAssetCapManager();\n\n        __MYieldToOne_init(name, symbol, yieldRecipient, admin, freezeManager, yieldRecipientManager, pauser);\n\n        _grantRole(ASSET_CAP_MANAGER_ROLE, assetCapManager);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IJMIExtension\n    function wrap(address asset, address recipient, uint256 amount) external onlySwapFacility {\n        // NOTE: `msg.sender` is always SwapFacility contract.\n        //       `ISwapFacility.msgSender()` is used to ensure that the original caller is passed to `_beforeWrap`.\n        _wrap(asset, ISwapFacility(msg.sender).msgSender(), recipient, amount);\n    }\n\n    /// @inheritdoc IJMIExtension\n    function replaceAssetWithM(address asset, address recipient, uint256 amount) external onlySwapFacility {\n        _replaceAssetWithM(asset, recipient, amount);\n    }\n\n    /* ============ Admin Controlled Interactive Functions ============ */\n\n    /// @inheritdoc IJMIExtension\n    function setAssetCap(address asset, uint256 cap) external onlyRole(ASSET_CAP_MANAGER_ROLE) {\n        _revertIfInvalidAsset(asset);\n\n        JMIExtensionStorageStruct storage $ = _getJMIExtensionStorageLocation();\n\n        if ($.assets[asset].cap == cap) return;\n\n        // NOTE: Fetch and store asset decimals only once.\n        if ($.assets[asset].decimals == 0) $.assets[asset].decimals = IERC20(asset).decimals();\n\n        $.assets[asset].cap = cap;\n\n        emit AssetCapSet(asset, cap);\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IJMIExtension\n    function assetBalanceOf(address asset) public view returns (uint256) {\n        return _getJMIExtensionStorageLocation().assets[asset].balance;\n    }\n\n    /// @inheritdoc IJMIExtension\n    function assetCap(address asset) public view returns (uint256) {\n        return _getJMIExtensionStorageLocation().assets[asset].cap;\n    }\n\n    /// @inheritdoc IJMIExtension\n    function assetDecimals(address asset) public view returns (uint8) {\n        return _getJMIExtensionStorageLocation().assets[asset].decimals;\n    }\n\n    /// @inheritdoc IJMIExtension\n    function totalAssets() public view returns (uint256) {\n        return _getJMIExtensionStorageLocation().totalAssets;\n    }\n\n    /// @inheritdoc IJMIExtension\n    function isAllowedAsset(address asset) public view returns (bool) {\n        return (asset == mToken) || (assetCap(asset) != 0);\n    }\n\n    /// @inheritdoc IJMIExtension\n    function isAllowedToWrap(address asset, uint256 amount) public view returns (bool) {\n        if (amount == 0) return false;\n\n        // NOTE: Allow any amount of M (primary asset) to be wrapped into JMI extension token.\n        if (asset == mToken) return true;\n\n        // NOTE: Check cap for other assets.\n        return assetCap(asset) >= (assetBalanceOf(asset) + amount);\n    }\n\n    /// @inheritdoc IJMIExtension\n    function isAllowedToUnwrap(uint256 amount) external view returns (bool) {\n        return amount != 0 && _mBacking() >= amount;\n    }\n\n    /// @inheritdoc IJMIExtension\n    function isAllowedToReplaceAssetWithM(address asset, uint256 amount) external view returns (bool) {\n        return amount != 0 && assetBalanceOf(asset) >= amount;\n    }\n\n    /// @inheritdoc IMYieldToOne\n    function yield() public view override(IMYieldToOne, MYieldToOne) returns (uint256) {\n        uint256 mBalance_ = _mBalanceOf(address(this));\n        uint256 mBacking_ = _mBacking();\n\n        unchecked {\n            return mBalance_ > mBacking_ ? mBalance_ - mBacking_ : 0;\n        }\n    }\n\n    /* ============ Hooks For Internal Interactive Functions ============ */\n\n    /**\n     * @dev   Hook called before wrapping `asset` into extension's tokens.\n     * @param asset     Address of the asset being deposited.\n     * @param account   The account initiating the wrap.\n     * @param recipient The address that will receive extension tokens.\n     * @param amount    The amount of `asset` being deposited.\n     */\n    function _beforeWrap(address asset, address account, address recipient, uint256 amount) internal view virtual {\n        if (!isAllowedToWrap(asset, amount)) revert AssetCapReached(asset);\n\n        super._beforeWrap(account, recipient, amount);\n    }\n\n    /**\n     * @dev   Hook called before unwrapping `amount` of extension tokens for M.\n     * @param account The account from which `amount` of tokens is burned.\n     * @param amount  The amount of tokens to burn.\n     */\n    function _beforeUnwrap(address account, uint256 amount) internal view virtual override {\n        _revertIfInsufficientMBacking(amount);\n\n        super._beforeUnwrap(account, amount);\n    }\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @notice Mint extension tokens by depositing `asset` tokens.\n     * @dev    `amount` must be formatted in the `asset` token's decimals.\n     * @param  asset     Address of the asset to deposit.\n     * @param  account   Address of the account initiating the wrap.\n     * @param  recipient Address that will receive the extension tokens.\n     * @param  amount    Amount of asset tokens to deposit.\n     */\n    function _wrap(address asset, address account, address recipient, uint256 amount) internal virtual {\n        _revertIfInvalidAsset(asset);\n        _revertIfInvalidRecipient(recipient);\n        _revertIfInsufficientAmount(amount);\n\n        // NOTE: MYieldToOne's `_beforeWrap` checks that `account` and `recipient` are not frozen.\n        _beforeWrap(asset, account, recipient, amount);\n\n        uint256 assetBalanceBefore_ = IERC20(asset).balanceOf(address(this));\n\n        // NOTE: Transfers asset from SwapFacility to this contract (amount is in asset decimals).\n        IERC20(asset).safeTransferFrom(msg.sender, address(this), amount);\n\n        // NOTE: Check actual amount received and revert if less than expected (to prevent fee on transfer tokens).\n        uint256 amountReceived_ = IERC20(asset).balanceOf(address(this)) - assetBalanceBefore_;\n        if (amountReceived_ < amount) revert InsufficientAssetReceived(asset, amount, amountReceived_);\n\n        // NOTE: Converts to extension amount and reverts in case it truncates to zero.\n        uint256 jmiAmount_ = _fromAssetToExtensionAmount(asset, amount);\n        _revertIfInsufficientAmount(jmiAmount_);\n\n        JMIExtensionStorageStruct storage $ = _getJMIExtensionStorageLocation();\n\n        // NOTE: Update non-M asset amount backing JMI extension token.\n        $.assets[asset].balance += UIntMath.safe240(amount);\n        $.totalAssets += jmiAmount_;\n\n        _mint(recipient, jmiAmount_);\n    }\n\n    /*\n     * @notice Allows a M holder to swap M for the `asset` token.\n     * @dev    `amount` MUST be formatted in the M token's decimals.\n     * @param  asset     Address of the asset being replaced.\n     * @param  recipient Address that will receive the `asset` token.\n     * @param  amount    Amount of M to swap for `asset` token.\n     */\n    function _replaceAssetWithM(address asset, address recipient, uint256 amount) internal virtual {\n        _requireNotPaused();\n        _revertIfInvalidAsset(asset);\n        _revertIfInvalidRecipient(recipient);\n        _revertIfInsufficientAmount(amount);\n\n        // NOTE: Converts to asset amount and reverts in case it truncates to zero.\n        uint256 assetAmount_ = _fromExtensionToAssetAmount(asset, amount);\n        _revertIfInsufficientAmount(assetAmount_);\n        _revertIfInsufficientAssetBacking(asset, assetAmount_);\n\n        JMIExtensionStorageStruct storage $ = _getJMIExtensionStorageLocation();\n\n        // NOTE: Update non-M asset amount backing JMI extension token.\n        // NOTE: No need to safe cast here since `balance` can't exceed uint240,\n        //       it will revert in `_revertIfInsufficientAssetBacking()` if `assetAmount_` is greater than `balance`.\n        $.assets[asset].balance -= uint240(assetAmount_);\n        $.totalAssets -= amount;\n\n        // NOTE: `msg.sender` is always SwapFacility contract.\n        // NOTE: The behavior of `IMTokenLike.transferFrom` is known, so its return can be ignored.\n        IMTokenLike(mToken).transferFrom(msg.sender, address(this), amount);\n        IERC20(asset).safeTransfer(recipient, assetAmount_);\n\n        emit AssetReplacedWithM(asset, assetAmount_, recipient, amount);\n    }\n\n    /* ============ Internal View Functions ============ */\n\n    /// @dev Returns the current supply of M backing the extension token.\n    function _mBacking() internal view returns (uint256) {\n        uint256 totalSupply_ = totalSupply();\n        uint256 totalAssets_ = totalAssets();\n\n        unchecked {\n            return totalSupply_ > totalAssets_ ? totalSupply_ - totalAssets_ : 0;\n        }\n    }\n\n    /**\n     * @dev   Reverts if `asset` is address(0) or M token.\n     *       `wrap(address recipient, uint256 amount)` MUST be used to wrap M.\n     * @param asset Address of an asset.\n     */\n    function _revertIfInvalidAsset(address asset) internal view {\n        if (asset == address(0) || asset == mToken) revert InvalidAsset(asset);\n    }\n\n    /**\n     * @dev   Reverts if there is not enough M backing to unwrap the requested amount.\n     * @param amount Amount of M to unwrap.\n     */\n    function _revertIfInsufficientMBacking(uint256 amount) internal view {\n        uint256 mBacking_ = _mBacking();\n        if (amount > mBacking_) revert InsufficientMBacking(amount, mBacking_);\n    }\n\n    /**\n     * @dev   Reverts if `amount` of `asset` is greater than the available balance held by the extension.\n     * @param asset  Address of an asset.\n     * @param amount Amount of `asset` to check.\n     */\n    function _revertIfInsufficientAssetBacking(address asset, uint256 amount) internal view {\n        uint256 assetBacking_ = assetBalanceOf(asset);\n        if (amount > assetBacking_) revert InsufficientAssetBacking(asset, amount, assetBacking_);\n    }\n\n    /**\n     * @dev    Converts `amount` from asset decimals to extension decimals.\n     * @param  asset  Address of an asset.\n     * @param  amount Amount in `asset` decimals.\n     * @return Amount in extension decimals.\n     */\n    function _fromAssetToExtensionAmount(address asset, uint256 amount) internal view returns (uint256) {\n        return _convertAmounts(assetDecimals(asset), M_DECIMALS, amount);\n    }\n\n    /**\n     * @dev    Converts `amount` from extension decimals to asset decimals.\n     * @param  asset  Address of an asset.\n     * @param  amount Amount in extension decimals.\n     * @return Amount in `asset` decimals.\n     */\n    function _fromExtensionToAssetAmount(address asset, uint256 amount) internal view returns (uint256) {\n        return _convertAmounts(M_DECIMALS, assetDecimals(asset), amount);\n    }\n\n    /* ============ Internal Pure Functions ============ */\n\n    /**\n     * @dev    Converts `amount` from `fromDecimals` to `toDecimals`.\n     * @param  fromDecimals The decimals of the input amount.\n     * @param  toDecimals   The decimals of the output amount.\n     * @param  amount       The amount to convert.\n     * @return The converted amount.\n     */\n    function _convertAmounts(uint8 fromDecimals, uint8 toDecimals, uint256 amount) internal pure returns (uint256) {\n        if (fromDecimals == toDecimals) return amount;\n\n        return\n            fromDecimals > toDecimals\n                ? amount / (10 ** (fromDecimals - toDecimals))\n                : amount * (10 ** (toDecimals - fromDecimals));\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f80fd5b50600436106104a9575f3560e01c806384b0196e11610277578063b7b7289911610162578063d505accf116100dd578063e3ee160e11610093578063e63ab1e911610079578063e63ab1e914610cc7578063e94a010214610cee578063ef55bec614610d45575f80fd5b8063e3ee160e14610c6a578063e583983614610c7d575f80fd5b8063d9169487116100c3578063d916948714610b7d578063dd62ed3e14610ba4578063e366da2c14610bfb575f80fd5b8063d505accf14610b57578063d547741f14610b6a575f80fd5b8063c9144ddb11610132578063c967891a11610118578063c967891a14610b0c578063cc4c5b6414610b14578063cf09299514610b44575f80fd5b8063c9144ddb14610af1578063c91f0c5314610af9575f80fd5b8063b7b7289914610a91578063bf376c7a14610aa4578063c3b6f93914610ab7578063c537bed014610ade575f80fd5b80639fd5a6cf116101f2578063a8afc01f116101c2578063aad12029116101a8578063aad1202914610a2c578063ace150a514610a3f578063ae06b7e414610a52575f80fd5b8063a8afc01f14610a11578063a9059cbb14610a19575f80fd5b80639fd5a6cf146109bd578063a08cb48b146109d0578063a0cc6a68146109e3578063a217fddf14610a0a575f80fd5b80638d1fdf2f1161024757806394f5a66e1161022d57806394f5a66e1461098f57806395d89b41146109a257806398abb5ea146109aa575f80fd5b80638d1fdf2f1461092557806391d1485414610938575f80fd5b806384b0196e146108d157806388a47d4d146108ec57806388b7ab63146108ff578063890afeff14610912575f80fd5b806339f47693116103975780635c975abb1161031257806370a08231116102e25780637ecebe00116102c85780637ecebe001461088f5780637f2eecc3146108a25780638456cb59146108c9575f80fd5b806370a0823114610840578063737a3ddd14610887575f80fd5b80635c975abb146107c957806362355638146107f357806363f156491461080657806364c2a2651461082d575f80fd5b806345c8b1a6116103675780634aa504d31161034d5780634aa504d314610790578063532992c5146107a35780635a049a70146107b6575f80fd5b806345c8b1a61461076a57806345cf012d1461077d575f80fd5b806339f47693146107205780633f4ba83a14610733578063406cf2291461073b5780634259dff914610743575f80fd5b8063248a9ca31161042757806330adf81f116103f7578063313ce567116103dd578063313ce567146106cd5780633644e5151461070557806336568abe1461070d575f80fd5b806330adf81f1461067f57806331234287146106a6575f80fd5b8063248a9ca3146105fa57806326987b601461063b57806328593984146106645780632f2ff15d1461066c575f80fd5b8063095ea7b31161047c578063170e207011610462578063170e2070146105ab57806318160ddd146105c057806323b872dd146105e7575f80fd5b8063095ea7b3146105855780631143a46914610598575f80fd5b806301e1d114146104ad57806301ffc9a7146104e357806306b3efd61461050657806306fdde0314610570575b5f80fd5b7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b01545b6040519081526020015b60405180910390f35b6104f66104f13660046149d7565b610d58565b60405190151581526020016104da565b6104d0610514366004614a35565b6001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b610578610df0565b6040516104da9190614a9c565b6104f6610593366004614aae565b610ea3565b6104f66105a6366004614ad8565b610eb8565b6105be6105b9366004614aef565b610ed4565b005b7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af100546104d0565b6104f66105f5366004614b60565b610f68565b6104d0610608366004614ad8565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b61064361105f565b6040516fffffffffffffffffffffffffffffffff90911681526020016104da565b6104d06110e5565b6105be61067a366004614b9e565b611115565b6104d07f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6104d07fa56d2bdf254c8533e707144802f9ebe3f93e4c7e3dbd92488f75e6c593e0c2af81565b7fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da1015460ff165b60405160ff90911681526020016104da565b6104d061115e565b6105be61071b366004614b9e565b6111a3565b6105be61072e366004614aae565b6111f4565b6105be6112c3565b6104d06112f8565b6104d07f4a5e9eb1ba56d04185ff75ebf0f4f42a3d7c88c35b4a90fa278437e0c9bdceca81565b6105be610778366004614a35565b611384565b6105be61078b366004614a35565b6113d8565b6104f661079e366004614aae565b611414565b6105be6107b1366004614bcc565b6114e1565b6105be6107c4366004614c12565b611500565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166104f6565b6105be610801366004614b60565b611520565b6104d07f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b3581565b6105be61083b366004614aae565b6115ed565b6104d061084e366004614a35565b6001600160a01b03165f9081527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af102602052604090205490565b6106f3600681565b6104d061089d366004614a35565b6117cd565b6104d07fd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de881565b6105be61180e565b6108d9611840565b6040516104da9796959493929190614c60565b6105be6108fa366004614b60565b61199b565b6105be61090d366004614dee565b611a08565b6104f6610920366004614aae565b611a37565b6105be610933366004614a35565b611aa3565b6104f6610946366004614b9e565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6105be61099d366004614e71565b611af7565b610578611c6e565b6104d06109b8366004614a35565b611c96565b6105be6109cb366004614f3f565b611cbd565b6105be6109de366004614fb0565b611ccd565b6104d07f7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a226781565b6104d05f81565b6105be611cf7565b6104f6610a27366004614aae565b611e0b565b6105be610a3a366004614aef565b611e17565b6105be610a4d366004614fb0565b611ea4565b610a797f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f627881565b6040516001600160a01b0390911681526020016104da565b6105be610a9f366004615016565b611ec4565b6105be610ab2366004614aae565b611edc565b610a797f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b81565b6104f6610aec366004614a35565b611fa8565b6104f6611ff5565b6105be610b0736600461506b565b612096565b6105be61220b565b7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af101546001600160a01b0316610a79565b6105be610b52366004614dee565b6122ef565b6105be610b6536600461512c565b61230f565b6105be610b78366004614b9e565b61231f565b6104d07f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742981565b6104d0610bb2366004615198565b6001600160a01b039182165f9081527fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da1006020908152604080832093909416825291909152205490565b6106f3610c09366004614a35565b6001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547e01000000000000000000000000000000000000000000000000000000000000900460ff1690565b6105be610c783660046151c4565b612362565b6104f6610c8b366004614a35565b6001600160a01b03165f9081527f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce00602052604090205460ff1690565b6104d07f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6104f6610cfc366004614aae565b6001600160a01b03919091165f9081527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a488860060209081526040808320938352929052205460ff1690565b6105be610d533660046151c4565b61238d565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610dea57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60607f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea1005b6002018054610e2290615245565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4e90615245565b8015610e995780601f10610e7057610100808354040283529160200191610e99565b820191905f5260205f20905b815481529060010190602001808311610e7c57829003601f168201915b5050505050905090565b5f610eaf3384846123ad565b50600192915050565b5f8115801590610dea575081610ecc6123c3565b101592915050565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b35610efe81612418565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce005f5b83811015610f6157610f5982868684818110610f3f57610f3f615296565b9050602002016020810190610f549190614a35565b612422565b600101610f21565b5050505050565b6001600160a01b0383165f9081527fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100602081815260408084203385529091528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146110465783811015611020576040517f192b9e4e00000000000000000000000000000000000000000000000000000000815233600482015260248101829052604481018590526064015b60405180910390fd5b6001600160a01b0386165f90815260208381526040808320338452909152902084820390555b61105186868661249b565b6001925050505b9392505050565b5f7f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b03166326987b606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110bc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e091906152c3565b905090565b5f806110f030612562565b90505f6110fb6123c3565b905080821161110a575f61110e565b8082035b9250505090565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461114e81612418565b6111588383612607565b50505050565b7f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea10080545f91904614611197576111926126d3565b61119d565b80600101545b91505090565b6001600160a01b03811633146111e5576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ef828261278e565b505050565b336001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f62781614611256576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf336001600160a01b031663d737d0c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611295573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112b991906152f2565b82612832565b5050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6112ed81612418565b6112f5612902565b50565b5f806113026110e5565b9050805f03611312575f91505090565b6040518181527fd1c22369a95f91ae16576036bba6372736ba109f257ad94dccb89e141762e2659060200160405180910390a161137f6113797fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af101546001600160a01b031690565b82612974565b919050565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b356113ae81612418565b6112bf7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce0083612422565b7f4a5e9eb1ba56d04185ff75ebf0f4f42a3d7c88c35b4a90fa278437e0c9bdceca61140281612418565b61140a6112f8565b506112bf82612a14565b5f815f0361142357505f610dea565b7f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316836001600160a01b03160361146457506001610dea565b816114c5846001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b6114cf919061533a565b6114d884611c96565b10159392505050565b6114f6846114ef8686612b13565b8484612b7a565b6111588484612b8e565b6115168561150e8787612b13565b858585612c10565b610f618585612b8e565b336001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f62781614611582576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ef83336001600160a01b031663d737d0c76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115e691906152f2565b8484612c20565b7fa56d2bdf254c8533e707144802f9ebe3f93e4c7e3dbd92488f75e6c593e0c2af61161781612418565b61162083612ec0565b6001600160a01b0383165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060208190526040909120548390036116675750505050565b6001600160a01b0384165f908152602082905260408120600101547e01000000000000000000000000000000000000000000000000000000000000900460ff16900361177b57836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061170d919061534d565b6001600160a01b0385165f908152602083905260409020600101805460ff929092167e01000000000000000000000000000000000000000000000000000000000000027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555b6001600160a01b0384165f818152602083815260409182902086905590518581527f70b5c8a095bb680742b58d79cdc18b0477268ac25a3a49141caf92ee01af5247910160405180910390a250505050565b5f7f1b21ba3f0a2135d61c468900b54084f04af8111bce0f8bbb6ab8c46d11afbd005b6001600160a01b039092165f90815260209290925250604090205490565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61183881612418565b6112f5612f49565b5f606080828080837f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea10060020146305f80604051908082528060200260200182016040528015611899578160200160208202803683370190505b507f0f0000000000000000000000000000000000000000000000000000000000000094939291908480546118cc90615245565b80601f01602080910402602001604051908101604052809291908181526020018280546118f890615245565b80156119435780601f1061191a57610100808354040283529160200191611943565b820191905f5260205f20905b81548152906001019060200180831161192657829003601f168201915b505050505094506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525093929190965096509650965096509650965090919293949596565b336001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f627816146119fd576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ef838383612fa4565b611a2087611a1a8989898989896131dc565b83613256565b611a2e8787878787876132a1565b50505050505050565b5f81158015906110585750816114d8846001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b35611acd81612418565b6112bf7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce008361330a565b5f611b00613382565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f81158015611b2c5750825b90505f8267ffffffffffffffff166001148015611b485750303b155b905081158015611b56575080155b15611b8d576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315611bee5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b611bfe8d8d8d8d8d8d8d8d6133aa565b8315611c5f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b60607fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100610e14565b5f7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b006117f0565b610f6185611a1a8787878761342b565b611cdf886114ef8a8a8a8a8a8a6131dc565b611ced8888888888886132a1565b5050505050505050565b611cff611ff5565b611d35576040517fb019ea3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fee580fdb4da10ea17aa673e6f5c8c2370b4166d6a94bc88900e5a96d0589e3ce611d5e61105f565b6040516fffffffffffffffffffffffffffffffff909116815260200160405180910390a16040517f81399be40000000000000000000000000000000000000000000000000000000081523060048201527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316906381399be4906024015f604051808303815f87803b158015611df9575f80fd5b505af1158015611158573d5f803e3d5ffd5b5f610eaf33848461249b565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b35611e4181612418565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce005f5b83811015610f6157611e9c82868684818110611e8257611e82615296565b9050602002016020810190611e979190614a35565b61330a565b600101611e64565b611eb6886114ef8a8a8a8a8a8a6134e8565b611ced888888888888613557565b611ed283611a1a8585612b13565b6111ef8383612b8e565b336001600160a01b037f000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f62781614611f3e576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf336001600160a01b031663d737d0c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f7d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fa191906152f2565b8383613664565b5f7f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316826001600160a01b03161480610dea5750611fed82611c96565b151592915050565b6040517f84af270f0000000000000000000000000000000000000000000000000000000081523060048201525f907f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316906384af270f90602401602060405180830381865afa158015612072573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e09190615368565b5f61209f613382565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f811580156120cb5750825b90505f8267ffffffffffffffff1660011480156120e75750303b155b9050811580156120f5575080155b1561212c576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561218d5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b61219c8c8c8c8c8c8c8c613739565b83156121fd5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050505050565b612213611ff5565b1561224a576040517f7a42736800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f5098de6eb11dbd1127cf4dcd5e960e3944d48a7570b9b1939cff715cb35c5a1861227361105f565b6040516fffffffffffffffffffffffffffffffff909116815260200160405180910390a17f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b031663a36e40fc6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611df9575f80fd5b61230187611a1a8989898989896134e8565b611a2e878787878787613557565b611a2e8761150e8989898961342b565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461235881612418565b611158838361278e565b6123748961150e8b8b8b8b8b8b6134e8565b612382898989898989613557565b505050505050505050565b61239f8961150e8b8b8b8b8b8b6131dc565b6123828989898989896132a1565b6123b883838361381b565b6111ef838383613850565b5f806123ed7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1005490565b90505f6110fb7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b015490565b6112f581336138c7565b6001600160a01b0381165f9081526020839052604090205460ff16612445575050565b6001600160a01b0381165f8181526020848152604091829020805460ff1916905590514281527f07d647ad688e085159820c1d8d030e5765cdc5274d4ee4065c6066b388a2ef5991015b60405180910390a25050565b6124a482613953565b6124af83838361399e565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516124f491815260200190565b60405180910390a3805f0361250857505050565b61251283826139db565b6001600160a01b038084165f9081527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af102602052604080822080548590039055918416815220805482019055505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301525f917f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b909116906370a0823190602401602060405180830381865afa1580156125e3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dea9190615387565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602081815260408084206001600160a01b038616855290915282205460ff166126ca575f848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556126803390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610dea565b5f915050610dea565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea100600201604051612726919061539e565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602081815260408084206001600160a01b038616855290915282205460ff16156126ca575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610dea565b61283b81613a65565b6128458282613aa1565b61284f33826139db565b6128593382613ab4565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b03169063a9059cbb906044016020604051808303815f875af11580156128dc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef9190615368565b565b61290a613b4c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b6001600160a01b0382165f8181527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af102602090815260408083208054860190557fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1008054860181559051858152909392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a3505050565b6001600160a01b038116612a54576040517f5dfd400c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af101547fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af100906001600160a01b0390811690831603612aaf575050565b6001810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040517f77f12a3c9f87d4602fe59bb8d2b68c7b516e0cacba414a53e74ea75d435dc18d905f90a25050565b604080517f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742960208201526001600160a01b03841691810191909152606081018290525f90611058906080015b60405160208183030381529060405280519060200120613ba7565b611158612b8985858585613c08565b613c43565b612b988282613e07565b6001600160a01b0382165f8181527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a488860060209081526040808320858452909152808220805460ff19166001179055518392917f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d8191a35050565b610f61612b898686868686613e95565b612c2984612ec0565b612c3282613953565b612c3b81613a65565b612c4784848484613edd565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015612ca4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc89190615387565b9050612cdf6001600160a01b038616333085613f33565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9082906001600160a01b038816906370a0823190602401602060405180830381865afa158015612d3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d629190615387565b612d6c919061540f565b905082811015612dc1576040517f83257a290000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024810184905260448101829052606401611017565b5f612dcc8785613faf565b9050612dd781613a65565b7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b00612e0185614020565b6001600160a01b0389165f9081526020839052604081206001018054909190612e4b9084907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16615422565b92506101000a8154817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555081816001015f828254612eb0919061533a565b90915550611ced90508683612974565b6001600160a01b0381161580612f0757507f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316816001600160a01b0316145b156112f5576040517f6f79c78a0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611017565b612f5161407d565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612956565b612fac61407d565b612fb583612ec0565b612fbe82613953565b612fc781613a65565b5f612fd284836140d9565b9050612fdd81613a65565b612fe7848261414a565b6001600160a01b0384165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b006020819052604082206001018054919284926130539084907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16615458565b92506101000a8154817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555082816001015f8282546130b8919061540f565b90915550506040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018490527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316906323b872dd906064016020604051808303815f875af1158015613146573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061316a9190615368565b5061317f6001600160a01b03861685846141f7565b836001600160a01b0316856001600160a01b03167f8a4ed1b1befccbe11caf6bc1f1f5eeb2c12b4dd806c6014c110bcd756118e8ec84866040516131cd929190918252602082015260400190565b60405180910390a35050505050565b604080517fd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de860208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0810183905260e081018290525f9061324b9061010001612b5f565b979650505050505050565b5f613262848484614228565b90505f8160058111156132775761327761548e565b036132825750505050565b61328d84848461426c565b156132985750505050565b61115881613c43565b336001600160a01b038616146132f4576040517f1c5939f30000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0386166024820152604401611017565b613302868686868686613557565b505050505050565b6001600160a01b0381165f9081526020839052604090205460ff161561332e575050565b6001600160a01b0381165f8181526020849052604090819020805460ff19166001179055517f68e0d8c112165d0949ce87205b719ed7d98c7401866c34a159f7c67c6f5620e79061248f9042815260200190565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610dea565b6133b26143a7565b6001600160a01b0384166133f2576040517f8de68f0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61340188888888878688613739565b6123827fa56d2bdf254c8533e707144802f9ebe3f93e4c7e3dbd92488f75e6c593e0c2af85612607565b5f613435826143e5565b6134408585856123ad565b6001600160a01b038086165f8181527f1b21ba3f0a2135d61c468900b54084f04af8111bce0f8bbb6ab8c46d11afbd00602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928101929092529181019290925291861660608201526080810185905260a081019190915260c081018390526134df9060e001612b5f565b95945050505050565b604080517f7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a226760208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0810183905260e081018290525f9061324b9061010001612b5f565b824211613599576040517f498ff9a200000000000000000000000000000000000000000000000000000000815242600482015260248101849052604401611017565b8142106135db576040517fb3fcd33e00000000000000000000000000000000000000000000000000000000815242600482015260248101839052604401611017565b6135e58682613e07565b6001600160a01b0386165f8181527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a488860060209081526040808320858452909152808220805460ff19166001179055518392917f98de503528ee59b575ef0c0a2576a82497bfc029a5685b209e9ec333479b10a591a361330286868661249b565b61366d82613953565b61367681613a65565b613681838383614428565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b6001600160a01b0316906323b872dd906064016020604051808303815f875af115801561370a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061372e9190615368565b506111ef8282612974565b6137416143a7565b6001600160a01b038216613781576040517f09d50edf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384166137c1576040517f7289db0e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6137cb8787614430565b6137d483614444565b6137dd816144b6565b6137e685612a14565b6137f05f85612607565b50611ced7f4a5e9eb1ba56d04185ff75ebf0f4f42a3d7c88c35b4a90fa278437e0c9bdceca83612607565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce006138468185614528565b6111588184614528565b6001600160a01b038381165f8181527fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259101612a07565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602090815260408083206001600160a01b038516845290915290205460ff166112bf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611017565b6001600160a01b0381166112f5576040517f17858bbe0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611017565b6139a661407d565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce006139d18133614528565b6138468185614528565b6001600160a01b0382165f9081527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1026020526040902054818110156111ef576040517fdb42144d0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810182905260448101839052606401611017565b805f036112f5576040517f77b8dde300000000000000000000000000000000000000000000000000000000815260048101829052602401611017565b613aaa81614585565b6112bf82826145d4565b6001600160a01b0382165f8181527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af10260209081526040808320805486900390557fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1008054869003815590518581529093917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101612a07565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16612900576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613bb061115e565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b5f805f613c16868686614606565b90925090505f826005811115613c2e57613c2e61548e565b14613c39578161324b565b61324b878261464e565b5f816005811115613c5657613c5661548e565b03613c5e5750565b6001816005811115613c7257613c7261548e565b03613ca9576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002816005811115613cbd57613cbd61548e565b03613cf4576040517f4be6321b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003816005811115613d0857613d0861548e565b03613d3f576040517fbf4bf5b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004816005811115613d5357613d5361548e565b03613d8a576040517fff551e8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005816005811115613d9e57613d9e61548e565b03613dd5576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382165f9081527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a48886006020908152604080832084845290915290205460ff16156112bf576040517fd309466d0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401611017565b5f805f613ea487878787614677565b90925090505f826005811115613ebc57613ebc61548e565b14613ec75781613ed1565b613ed1888261464e565b98975050505050505050565b613ee78482611414565b613f28576040517f74f091620000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611017565b611158838383614428565b6040516001600160a01b0384811660248301528381166044830152606482018390526111589186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050614777565b5f611058614018846001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547e01000000000000000000000000000000000000000000000000000000000000900460ff1690565b6006846147fc565b5f7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115614079576040517f2a49c10d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615612900576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6110586006614144856001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547e01000000000000000000000000000000000000000000000000000000000000900460ff1690565b846147fc565b6001600160a01b0382165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16808211156111ef576040517f7c6781510000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810183905260448101829052606401611017565b6040516001600160a01b038381166024830152604482018390526111ef91859182169063a9059cbb90606401613f68565b5f805f6142358585614869565b90925090505f82600581111561424d5761424d61548e565b146142585781614262565b614262868261464e565b9695505050505050565b5f805f856001600160a01b0316858560405160240161428c9291906154bb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1626ba7e000000000000000000000000000000000000000000000000000000001790525161430d91906154d3565b5f60405180830381855afa9150503d805f8114614345576040519150601f19603f3d011682016040523d82523d5f602084013e61434a565b606091505b509150915081801561435e57506020815110155b8015614262575080517f1626ba7e000000000000000000000000000000000000000000000000000000009061439c9083016020908101908401615387565b149695505050505050565b6143af6148ad565b612900576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b804211156112f5576040517ff88f049000000000000000000000000000000000000000000000000000000000815260048101829052426024820152604401611017565b61381b61407d565b6144386143a7565b6112bf828260066148cb565b61444c6143a7565b6001600160a01b03811661448c576040517f6cbbd1d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b3582612607565b6144be6143a7565b6001600160a01b0381166144fe576040517f042d717b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a82612607565b6001600160a01b0381165f9081526020839052604090205460ff16156112bf576040517f4f2a367e0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611017565b5f61458e6123c3565b9050808211156112bf576040517f3dbc0a1b0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401611017565b6145dc61407d565b6112bf7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce0083614528565b5f80601b60ff84901c017f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841661463f87838884614677565b9350935050505b935093915050565b5f816001600160a01b0316836001600160a01b03161461466f576005611058565b505f92915050565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156146ac5750600390505f61476e565b8460ff16601b141580156146c457508460ff16601c14155b156146d45750600490505f61476e565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614724573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811615614765575f81614769565b60015f5b915091505b94509492505050565b5f8060205f8451602086015f885af180614796576040513d5f823e3d81fd5b50505f513d915081156147ad5780600114156147ba565b6001600160a01b0384163b155b15611158576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611017565b5f8260ff168460ff1603614811575080611058565b8260ff168460ff16116148425761482884846154e9565b61483390600a61561b565b61483d9083615629565b614861565b61484c83856154e9565b61485790600a61561b565b6148619083615640565b949350505050565b5f80825160411461487f5750600290505f6148a6565b6020830151604084015160608501515f1a919061489e87848484614677565b945094505050505b9250929050565b5f6148b6613382565b5468010000000000000000900460ff16919050565b6148d36143a7565b6148dc83614956565b7fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da101805460ff191660ff83161790557fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da1007fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da102610f6184826156bc565b61495e6143a7565b6112f58161496a6143a7565b6112f5816149766143a7565b7f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea1007f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea1026149c283826156bc565b504681556149ce6126d3565b60019091015550565b5f602082840312156149e7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611058575f80fd5b6001600160a01b03811681146112f5575f80fd5b803561137f81614a16565b5f60208284031215614a45575f80fd5b813561105881614a16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6110586020830184614a50565b5f8060408385031215614abf575f80fd5b8235614aca81614a16565b946020939093013593505050565b5f60208284031215614ae8575f80fd5b5035919050565b5f8060208385031215614b00575f80fd5b823567ffffffffffffffff811115614b16575f80fd5b8301601f81018513614b26575f80fd5b803567ffffffffffffffff811115614b3c575f80fd5b8560208260051b8401011115614b50575f80fd5b6020919091019590945092505050565b5f805f60608486031215614b72575f80fd5b8335614b7d81614a16565b92506020840135614b8d81614a16565b929592945050506040919091013590565b5f8060408385031215614baf575f80fd5b823591506020830135614bc181614a16565b809150509250929050565b5f805f8060808587031215614bdf575f80fd5b8435614bea81614a16565b966020860135965060408601359560600135945092505050565b60ff811681146112f5575f80fd5b5f805f805f60a08688031215614c26575f80fd5b8535614c3181614a16565b9450602086013593506040860135614c4881614c04565b94979396509394606081013594506080013592915050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e060208201525f614c9a60e0830189614a50565b8281036040840152614cac8189614a50565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614d01578351835260209384019390920191600101614ce3565b50909b9a5050505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112614d4e575f80fd5b8135602083015f8067ffffffffffffffff841115614d6e57614d6e614d12565b506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85018116603f0116810181811067ffffffffffffffff82111715614dbb57614dbb614d12565b604052838152905080828401871015614dd2575f80fd5b838360208301375f602085830101528094505050505092915050565b5f805f805f805f60e0888a031215614e04575f80fd5b8735614e0f81614a16565b96506020880135614e1f81614a16565b955060408801359450606088013593506080880135925060a0880135915060c088013567ffffffffffffffff811115614e56575f80fd5b614e628a828b01614d3f565b91505092959891949750929550565b5f805f805f805f80610100898b031215614e89575f80fd5b883567ffffffffffffffff811115614e9f575f80fd5b614eab8b828c01614d3f565b985050602089013567ffffffffffffffff811115614ec7575f80fd5b614ed38b828c01614d3f565b9750506040890135614ee481614a16565b95506060890135614ef481614a16565b94506080890135614f0481614a16565b935060a0890135614f1481614a16565b9250614f2260c08a01614a2a565b9150614f3060e08a01614a2a565b90509295985092959890939650565b5f805f805f60a08688031215614f53575f80fd5b8535614f5e81614a16565b94506020860135614f6e81614a16565b93506040860135925060608601359150608086013567ffffffffffffffff811115614f97575f80fd5b614fa388828901614d3f565b9150509295509295909350565b5f805f805f805f80610100898b031215614fc8575f80fd5b8835614fd381614a16565b97506020890135614fe381614a16565b979a9799505050506040860135956060810135956080820135955060a0820135945060c0820135935060e0909101359150565b5f805f60608486031215615028575f80fd5b833561503381614a16565b925060208401359150604084013567ffffffffffffffff811115615055575f80fd5b61506186828701614d3f565b9150509250925092565b5f805f805f805f60e0888a031215615081575f80fd5b873567ffffffffffffffff811115615097575f80fd5b6150a38a828b01614d3f565b975050602088013567ffffffffffffffff8111156150bf575f80fd5b6150cb8a828b01614d3f565b96505060408801356150dc81614a16565b945060608801356150ec81614a16565b935060808801356150fc81614a16565b925060a088013561510c81614a16565b915060c088013561511c81614a16565b8091505092959891949750929550565b5f805f805f805f60e0888a031215615142575f80fd5b873561514d81614a16565b9650602088013561515d81614a16565b95506040880135945060608801359350608088013561517b81614c04565b9699959850939692959460a0840135945060c09093013592915050565b5f80604083850312156151a9575f80fd5b82356151b481614a16565b91506020830135614bc181614a16565b5f805f805f805f805f6101208a8c0312156151dd575f80fd5b89356151e881614a16565b985060208a01356151f881614a16565b975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013561522481614c04565b989b979a50959894979396929550929360e081013593506101000135919050565b600181811c9082168061525957607f821691505b602082108103615290577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156152d3575f80fd5b81516fffffffffffffffffffffffffffffffff81168114611058575f80fd5b5f60208284031215615302575f80fd5b815161105881614a16565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610dea57610dea61530d565b5f6020828403121561535d575f80fd5b815161105881614c04565b5f60208284031215615378575f80fd5b81518015158114611058575f80fd5b5f60208284031215615397575f80fd5b5051919050565b5f8083546153ab81615245565b6001821680156153c257600181146153d757615404565b60ff1983168652811515820286019350615404565b865f5260205f205f5b838110156153fc578154888201526001909101906020016153e0565b505081860193505b509195945050505050565b81810381811115610dea57610dea61530d565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181168382160190811115610dea57610dea61530d565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8281168282160390811115610dea57610dea61530d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f6148616040830184614a50565b5f82518060208501845e5f920191825250919050565b60ff8281168282160390811115610dea57610dea61530d565b6001815b6001841115614646578085048111156155215761552161530d565b600184161561552f57908102905b60019390931c928002615506565b5f8261554b57506001610dea565b8161555757505f610dea565b816001811461556d576002811461557757615593565b6001915050610dea565b60ff8411156155885761558861530d565b50506001821b610dea565b5060208310610133831016604e8410600b84101617156155b6575081810a610dea565b6155e17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615502565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156156135761561361530d565b029392505050565b5f61105860ff84168361553d565b8082028115828204841417610dea57610dea61530d565b5f82615673577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b601f8211156111ef57805f5260205f20601f840160051c8101602085101561569d5750805b601f840160051c820191505b81811015610f61575f81556001016156a9565b815167ffffffffffffffff8111156156d6576156d6614d12565b6156ea816156e48454615245565b84615678565b6020601f82116001811461573b575f83156157055750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455610f61565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b828110156157885787850151825560209485019460019092019101615768565b50848210156157c457868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220add2fadee0a8f76e9df2259280327dc2ab1f1ef6fcde5a3f9accd646c8eddf9f64736f6c634300081a0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"appendCBOR":true,"bytecodeHash":"ipfs","useLiteralContent":false},"optimizer":{"enabled":true,"runs":19999},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@openzeppelin/contracts/=lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/","safe-smart-account/=lib/common/lib/safe-utils/lib/safe-smart-account/contracts/","@ensdomains/=lib/uniswap-v4-periphery/lib/v4-core/node_modules/@ensdomains/","@openzeppelin/contracts-upgradeable/=lib/common/lib/openzeppelin-contracts-upgradeable/contracts/","@uniswap/v4-core/=lib/uniswap-v4-periphery/lib/v4-core/","common/=lib/common/","ds-test/=lib/uniswap-v4-periphery/lib/v4-core/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/common/lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","forge-gas-snapshot/=lib/uniswap-v4-periphery/lib/permit2/lib/forge-gas-snapshot/src/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/common/lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","hardhat/=lib/uniswap-v4-periphery/lib/v4-core/node_modules/hardhat/","openzeppelin-contracts-upgradeable/=lib/common/lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/common/lib/openzeppelin-contracts/","openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/","permit2/=lib/uniswap-v4-periphery/lib/permit2/","safe-utils/=lib/common/lib/safe-utils/src/","solidity-http/=lib/common/lib/safe-utils/lib/solidity-http/src/","solidity-stringutils/=lib/common/lib/safe-utils/lib/solidity-stringutils/","solmate/=lib/uniswap-v4-periphery/lib/v4-core/lib/solmate/","uniswap-v4-periphery/=lib/uniswap-v4-periphery/","v4-core/=lib/uniswap-v4-periphery/lib/v4-core/src/","wrapped-m-token/=lib/wrapped-m-token/"],"viaIR":false},"optimization_runs":19999,"sourcify_repo_url":null,"decoded_constructor_args":[["0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b",{"internalType":"address","name":"mToken","type":"address"}],["0xB6807116b3B1B321a390594e31ECD6e0076f6278",{"internalType":"address","name":"swapFacility","type":"address"}]],"compiler_version":"v0.8.26+commit.8a97fa7a","is_verified_via_verifier_alliance":false,"verified_at":"2026-05-12T10:56:23.977485Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60c060405234801561000f575f80fd5b50604051615a2e380380615a2e83398101604081905261002e9161016a565b8181818161003a61009d565b6001600160a01b03821660808190526100665760405163b01d5e2b60e01b815260040160405180910390fd5b6001600160a01b03811660a081905261009257604051636880ffc960e11b815260040160405180910390fd5b50505050505061019b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100ed5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b039081161461014c5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b80516001600160a01b0381168114610165575f80fd5b919050565b5f806040838503121561017b575f80fd5b6101848361014f565b91506101926020840161014f565b90509250929050565b60805160a0516158096102255f395f8181610a57015281816111ff0152818161152b015281816119a60152611ee701525f8181610abc015281816110620152818161142501528181611db001528181611fab01528181612025015281816122990152818161259c0152818161288e01528181612ed3015281816130f801526136bc01526158095ff3fe608060405234801561000f575f80fd5b50600436106104a9575f3560e01c806384b0196e11610277578063b7b7289911610162578063d505accf116100dd578063e3ee160e11610093578063e63ab1e911610079578063e63ab1e914610cc7578063e94a010214610cee578063ef55bec614610d45575f80fd5b8063e3ee160e14610c6a578063e583983614610c7d575f80fd5b8063d9169487116100c3578063d916948714610b7d578063dd62ed3e14610ba4578063e366da2c14610bfb575f80fd5b8063d505accf14610b57578063d547741f14610b6a575f80fd5b8063c9144ddb11610132578063c967891a11610118578063c967891a14610b0c578063cc4c5b6414610b14578063cf09299514610b44575f80fd5b8063c9144ddb14610af1578063c91f0c5314610af9575f80fd5b8063b7b7289914610a91578063bf376c7a14610aa4578063c3b6f93914610ab7578063c537bed014610ade575f80fd5b80639fd5a6cf116101f2578063a8afc01f116101c2578063aad12029116101a8578063aad1202914610a2c578063ace150a514610a3f578063ae06b7e414610a52575f80fd5b8063a8afc01f14610a11578063a9059cbb14610a19575f80fd5b80639fd5a6cf146109bd578063a08cb48b146109d0578063a0cc6a68146109e3578063a217fddf14610a0a575f80fd5b80638d1fdf2f1161024757806394f5a66e1161022d57806394f5a66e1461098f57806395d89b41146109a257806398abb5ea146109aa575f80fd5b80638d1fdf2f1461092557806391d1485414610938575f80fd5b806384b0196e146108d157806388a47d4d146108ec57806388b7ab63146108ff578063890afeff14610912575f80fd5b806339f47693116103975780635c975abb1161031257806370a08231116102e25780637ecebe00116102c85780637ecebe001461088f5780637f2eecc3146108a25780638456cb59146108c9575f80fd5b806370a0823114610840578063737a3ddd14610887575f80fd5b80635c975abb146107c957806362355638146107f357806363f156491461080657806364c2a2651461082d575f80fd5b806345c8b1a6116103675780634aa504d31161034d5780634aa504d314610790578063532992c5146107a35780635a049a70146107b6575f80fd5b806345c8b1a61461076a57806345cf012d1461077d575f80fd5b806339f47693146107205780633f4ba83a14610733578063406cf2291461073b5780634259dff914610743575f80fd5b8063248a9ca31161042757806330adf81f116103f7578063313ce567116103dd578063313ce567146106cd5780633644e5151461070557806336568abe1461070d575f80fd5b806330adf81f1461067f57806331234287146106a6575f80fd5b8063248a9ca3146105fa57806326987b601461063b57806328593984146106645780632f2ff15d1461066c575f80fd5b8063095ea7b31161047c578063170e207011610462578063170e2070146105ab57806318160ddd146105c057806323b872dd146105e7575f80fd5b8063095ea7b3146105855780631143a46914610598575f80fd5b806301e1d114146104ad57806301ffc9a7146104e357806306b3efd61461050657806306fdde0314610570575b5f80fd5b7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b01545b6040519081526020015b60405180910390f35b6104f66104f13660046149d7565b610d58565b60405190151581526020016104da565b6104d0610514366004614a35565b6001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b610578610df0565b6040516104da9190614a9c565b6104f6610593366004614aae565b610ea3565b6104f66105a6366004614ad8565b610eb8565b6105be6105b9366004614aef565b610ed4565b005b7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af100546104d0565b6104f66105f5366004614b60565b610f68565b6104d0610608366004614ad8565b5f9081527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015490565b61064361105f565b6040516fffffffffffffffffffffffffffffffff90911681526020016104da565b6104d06110e5565b6105be61067a366004614b9e565b611115565b6104d07f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b6104d07fa56d2bdf254c8533e707144802f9ebe3f93e4c7e3dbd92488f75e6c593e0c2af81565b7fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da1015460ff165b60405160ff90911681526020016104da565b6104d061115e565b6105be61071b366004614b9e565b6111a3565b6105be61072e366004614aae565b6111f4565b6105be6112c3565b6104d06112f8565b6104d07f4a5e9eb1ba56d04185ff75ebf0f4f42a3d7c88c35b4a90fa278437e0c9bdceca81565b6105be610778366004614a35565b611384565b6105be61078b366004614a35565b6113d8565b6104f661079e366004614aae565b611414565b6105be6107b1366004614bcc565b6114e1565b6105be6107c4366004614c12565b611500565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff166104f6565b6105be610801366004614b60565b611520565b6104d07f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b3581565b6105be61083b366004614aae565b6115ed565b6104d061084e366004614a35565b6001600160a01b03165f9081527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af102602052604090205490565b6106f3600681565b6104d061089d366004614a35565b6117cd565b6104d07fd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de881565b6105be61180e565b6108d9611840565b6040516104da9796959493929190614c60565b6105be6108fa366004614b60565b61199b565b6105be61090d366004614dee565b611a08565b6104f6610920366004614aae565b611a37565b6105be610933366004614a35565b611aa3565b6104f6610946366004614b9e565b5f9182527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6105be61099d366004614e71565b611af7565b610578611c6e565b6104d06109b8366004614a35565b611c96565b6105be6109cb366004614f3f565b611cbd565b6105be6109de366004614fb0565b611ccd565b6104d07f7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a226781565b6104d05f81565b6105be611cf7565b6104f6610a27366004614aae565b611e0b565b6105be610a3a366004614aef565b611e17565b6105be610a4d366004614fb0565b611ea4565b610a797f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016104da565b6105be610a9f366004615016565b611ec4565b6105be610ab2366004614aae565b611edc565b610a797f000000000000000000000000000000000000000000000000000000000000000081565b6104f6610aec366004614a35565b611fa8565b6104f6611ff5565b6105be610b0736600461506b565b612096565b6105be61220b565b7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af101546001600160a01b0316610a79565b6105be610b52366004614dee565b6122ef565b6105be610b6536600461512c565b61230f565b6105be610b78366004614b9e565b61231f565b6104d07f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742981565b6104d0610bb2366004615198565b6001600160a01b039182165f9081527fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da1006020908152604080832093909416825291909152205490565b6106f3610c09366004614a35565b6001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547e01000000000000000000000000000000000000000000000000000000000000900460ff1690565b6105be610c783660046151c4565b612362565b6104f6610c8b366004614a35565b6001600160a01b03165f9081527f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce00602052604090205460ff1690565b6104d07f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a81565b6104f6610cfc366004614aae565b6001600160a01b03919091165f9081527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a488860060209081526040808320938352929052205460ff1690565b6105be610d533660046151c4565b61238d565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b000000000000000000000000000000000000000000000000000000001480610dea57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316145b92915050565b60607f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea1005b6002018054610e2290615245565b80601f0160208091040260200160405190810160405280929190818152602001828054610e4e90615245565b8015610e995780601f10610e7057610100808354040283529160200191610e99565b820191905f5260205f20905b815481529060010190602001808311610e7c57829003601f168201915b5050505050905090565b5f610eaf3384846123ad565b50600192915050565b5f8115801590610dea575081610ecc6123c3565b101592915050565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b35610efe81612418565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce005f5b83811015610f6157610f5982868684818110610f3f57610f3f615296565b9050602002016020810190610f549190614a35565b612422565b600101610f21565b5050505050565b6001600160a01b0383165f9081527fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100602081815260408084203385529091528220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146110465783811015611020576040517f192b9e4e00000000000000000000000000000000000000000000000000000000815233600482015260248101829052604481018590526064015b60405180910390fd5b6001600160a01b0386165f90815260208381526040808320338452909152902084820390555b61105186868661249b565b6001925050505b9392505050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166326987b606040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110bc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e091906152c3565b905090565b5f806110f030612562565b90505f6110fb6123c3565b905080821161110a575f61110e565b8082035b9250505090565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461114e81612418565b6111588383612607565b50505050565b7f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea10080545f91904614611197576111926126d3565b61119d565b80600101545b91505090565b6001600160a01b03811633146111e5576040517f6697b23200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ef828261278e565b505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611256576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf336001600160a01b031663d737d0c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611295573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112b991906152f2565b82612832565b5050565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a6112ed81612418565b6112f5612902565b50565b5f806113026110e5565b9050805f03611312575f91505090565b6040518181527fd1c22369a95f91ae16576036bba6372736ba109f257ad94dccb89e141762e2659060200160405180910390a161137f6113797fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af101546001600160a01b031690565b82612974565b919050565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b356113ae81612418565b6112bf7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce0083612422565b7f4a5e9eb1ba56d04185ff75ebf0f4f42a3d7c88c35b4a90fa278437e0c9bdceca61140281612418565b61140a6112f8565b506112bf82612a14565b5f815f0361142357505f610dea565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03160361146457506001610dea565b816114c5846001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b6114cf919061533a565b6114d884611c96565b10159392505050565b6114f6846114ef8686612b13565b8484612b7a565b6111588484612b8e565b6115168561150e8787612b13565b858585612c10565b610f618585612b8e565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611582576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ef83336001600160a01b031663d737d0c76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115e691906152f2565b8484612c20565b7fa56d2bdf254c8533e707144802f9ebe3f93e4c7e3dbd92488f75e6c593e0c2af61161781612418565b61162083612ec0565b6001600160a01b0383165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060208190526040909120548390036116675750505050565b6001600160a01b0384165f908152602082905260408120600101547e01000000000000000000000000000000000000000000000000000000000000900460ff16900361177b57836001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156116e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061170d919061534d565b6001600160a01b0385165f908152602083905260409020600101805460ff929092167e01000000000000000000000000000000000000000000000000000000000000027fff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9092169190911790555b6001600160a01b0384165f818152602083815260409182902086905590518581527f70b5c8a095bb680742b58d79cdc18b0477268ac25a3a49141caf92ee01af5247910160405180910390a250505050565b5f7f1b21ba3f0a2135d61c468900b54084f04af8111bce0f8bbb6ab8c46d11afbd005b6001600160a01b039092165f90815260209290925250604090205490565b7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a61183881612418565b6112f5612f49565b5f606080828080837f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea10060020146305f80604051908082528060200260200182016040528015611899578160200160208202803683370190505b507f0f0000000000000000000000000000000000000000000000000000000000000094939291908480546118cc90615245565b80601f01602080910402602001604051908101604052809291908181526020018280546118f890615245565b80156119435780601f1061191a57610100808354040283529160200191611943565b820191905f5260205f20905b81548152906001019060200180831161192657829003601f168201915b505050505094506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525093929190965096509650965096509650965090919293949596565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146119fd576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111ef838383612fa4565b611a2087611a1a8989898989896131dc565b83613256565b611a2e8787878787876132a1565b50505050505050565b5f81158015906110585750816114d8846001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b35611acd81612418565b6112bf7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce008361330a565b5f611b00613382565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f81158015611b2c5750825b90505f8267ffffffffffffffff166001148015611b485750303b155b905081158015611b56575080155b15611b8d576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001660011785558315611bee5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b611bfe8d8d8d8d8d8d8d8d6133aa565b8315611c5f5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050505050565b60607fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100610e14565b5f7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b006117f0565b610f6185611a1a8787878761342b565b611cdf886114ef8a8a8a8a8a8a6131dc565b611ced8888888888886132a1565b5050505050505050565b611cff611ff5565b611d35576040517fb019ea3500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fee580fdb4da10ea17aa673e6f5c8c2370b4166d6a94bc88900e5a96d0589e3ce611d5e61105f565b6040516fffffffffffffffffffffffffffffffff909116815260200160405180910390a16040517f81399be40000000000000000000000000000000000000000000000000000000081523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906381399be4906024015f604051808303815f87803b158015611df9575f80fd5b505af1158015611158573d5f803e3d5ffd5b5f610eaf33848461249b565b7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b35611e4181612418565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce005f5b83811015610f6157611e9c82868684818110611e8257611e82615296565b9050602002016020810190611e979190614a35565b61330a565b600101611e64565b611eb6886114ef8a8a8a8a8a8a6134e8565b611ced888888888888613557565b611ed283611a1a8585612b13565b6111ef8383612b8e565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611f3e576040517f2bfe1b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf336001600160a01b031663d737d0c76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f7d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fa191906152f2565b8383613664565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03161480610dea5750611fed82611c96565b151592915050565b6040517f84af270f0000000000000000000000000000000000000000000000000000000081523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906384af270f90602401602060405180830381865afa158015612072573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e09190615368565b5f61209f613382565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f811580156120cb5750825b90505f8267ffffffffffffffff1660011480156120e75750303b155b9050811580156120f5575080155b1561212c576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561218d5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b61219c8c8c8c8c8c8c8c613739565b83156121fd5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050505050505050565b612213611ff5565b1561224a576040517f7a42736800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f5098de6eb11dbd1127cf4dcd5e960e3944d48a7570b9b1939cff715cb35c5a1861227361105f565b6040516fffffffffffffffffffffffffffffffff909116815260200160405180910390a17f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a36e40fc6040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611df9575f80fd5b61230187611a1a8989898989896134e8565b611a2e878787878787613557565b611a2e8761150e8989898961342b565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602052604090206001015461235881612418565b611158838361278e565b6123748961150e8b8b8b8b8b8b6134e8565b612382898989898989613557565b505050505050505050565b61239f8961150e8b8b8b8b8b8b6131dc565b6123828989898989896132a1565b6123b883838361381b565b6111ef838383613850565b5f806123ed7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1005490565b90505f6110fb7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b015490565b6112f581336138c7565b6001600160a01b0381165f9081526020839052604090205460ff16612445575050565b6001600160a01b0381165f8181526020848152604091829020805460ff1916905590514281527f07d647ad688e085159820c1d8d030e5765cdc5274d4ee4065c6066b388a2ef5991015b60405180910390a25050565b6124a482613953565b6124af83838361399e565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516124f491815260200190565b60405180910390a3805f0361250857505050565b61251283826139db565b6001600160a01b038084165f9081527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af102602052604080822080548590039055918416815220805482019055505050565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0382811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906370a0823190602401602060405180830381865afa1580156125e3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610dea9190615387565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602081815260408084206001600160a01b038616855290915282205460ff166126ca575f848152602082815260408083206001600160a01b03871684529091529020805460ff191660011790556126803390565b6001600160a01b0316836001600160a01b0316857f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a46001915050610dea565b5f915050610dea565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea100600201604051612726919061539e565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602081815260408084206001600160a01b038616855290915282205460ff16156126ca575f848152602082815260408083206001600160a01b0387168085529252808320805460ff1916905551339287917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a46001915050610dea565b61283b81613a65565b6128458282613aa1565b61284f33826139db565b6128593382613ab4565b6040517fa9059cbb000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303815f875af11580156128dc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef9190615368565b565b61290a613b4c565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a150565b6001600160a01b0382165f8181527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af102602090815260408083208054860190557fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1008054860181559051858152909392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a3505050565b6001600160a01b038116612a54576040517f5dfd400c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af101547fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af100906001600160a01b0390811690831603612aaf575050565b6001810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0384169081179091556040517f77f12a3c9f87d4602fe59bb8d2b68c7b516e0cacba414a53e74ea75d435dc18d905f90a25050565b604080517f158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a159742960208201526001600160a01b03841691810191909152606081018290525f90611058906080015b60405160208183030381529060405280519060200120613ba7565b611158612b8985858585613c08565b613c43565b612b988282613e07565b6001600160a01b0382165f8181527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a488860060209081526040808320858452909152808220805460ff19166001179055518392917f1cdd46ff242716cdaa72d159d339a485b3438398348d68f09d7c8c0a59353d8191a35050565b610f61612b898686868686613e95565b612c2984612ec0565b612c3282613953565b612c3b81613a65565b612c4784848484613edd565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015612ca4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc89190615387565b9050612cdf6001600160a01b038616333085613f33565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9082906001600160a01b038816906370a0823190602401602060405180830381865afa158015612d3e573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d629190615387565b612d6c919061540f565b905082811015612dc1576040517f83257a290000000000000000000000000000000000000000000000000000000081526001600160a01b03871660048201526024810184905260448101829052606401611017565b5f612dcc8785613faf565b9050612dd781613a65565b7f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b00612e0185614020565b6001600160a01b0389165f9081526020839052604081206001018054909190612e4b9084907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16615422565b92506101000a8154817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555081816001015f828254612eb0919061533a565b90915550611ced90508683612974565b6001600160a01b0381161580612f0757507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316145b156112f5576040517f6f79c78a0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611017565b612f5161407d565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300805460ff191660011781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25833612956565b612fac61407d565b612fb583612ec0565b612fbe82613953565b612fc781613a65565b5f612fd284836140d9565b9050612fdd81613a65565b612fe7848261414a565b6001600160a01b0384165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b006020819052604082206001018054919284926130539084907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16615458565b92506101000a8154817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555082816001015f8282546130b8919061540f565b90915550506040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303815f875af1158015613146573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061316a9190615368565b5061317f6001600160a01b03861685846141f7565b836001600160a01b0316856001600160a01b03167f8a4ed1b1befccbe11caf6bc1f1f5eeb2c12b4dd806c6014c110bcd756118e8ec84866040516131cd929190918252602082015260400190565b60405180910390a35050505050565b604080517fd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de860208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0810183905260e081018290525f9061324b9061010001612b5f565b979650505050505050565b5f613262848484614228565b90505f8160058111156132775761327761548e565b036132825750505050565b61328d84848461426c565b156132985750505050565b61115881613c43565b336001600160a01b038616146132f4576040517f1c5939f30000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0386166024820152604401611017565b613302868686868686613557565b505050505050565b6001600160a01b0381165f9081526020839052604090205460ff161561332e575050565b6001600160a01b0381165f8181526020849052604090819020805460ff19166001179055517f68e0d8c112165d0949ce87205b719ed7d98c7401866c34a159f7c67c6f5620e79061248f9042815260200190565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00610dea565b6133b26143a7565b6001600160a01b0384166133f2576040517f8de68f0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61340188888888878688613739565b6123827fa56d2bdf254c8533e707144802f9ebe3f93e4c7e3dbd92488f75e6c593e0c2af85612607565b5f613435826143e5565b6134408585856123ad565b6001600160a01b038086165f8181527f1b21ba3f0a2135d61c468900b54084f04af8111bce0f8bbb6ab8c46d11afbd00602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928101929092529181019290925291861660608201526080810185905260a081019190915260c081018390526134df9060e001612b5f565b95945050505050565b604080517f7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a226760208201526001600160a01b038089169282019290925290861660608201526080810185905260a0810184905260c0810183905260e081018290525f9061324b9061010001612b5f565b824211613599576040517f498ff9a200000000000000000000000000000000000000000000000000000000815242600482015260248101849052604401611017565b8142106135db576040517fb3fcd33e00000000000000000000000000000000000000000000000000000000815242600482015260248101839052604401611017565b6135e58682613e07565b6001600160a01b0386165f8181527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a488860060209081526040808320858452909152808220805460ff19166001179055518392917f98de503528ee59b575ef0c0a2576a82497bfc029a5685b209e9ec333479b10a591a361330286868661249b565b61366d82613953565b61367681613a65565b613681838383614428565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303815f875af115801561370a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061372e9190615368565b506111ef8282612974565b6137416143a7565b6001600160a01b038216613781576040517f09d50edf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384166137c1576040517f7289db0e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6137cb8787614430565b6137d483614444565b6137dd816144b6565b6137e685612a14565b6137f05f85612607565b50611ced7f4a5e9eb1ba56d04185ff75ebf0f4f42a3d7c88c35b4a90fa278437e0c9bdceca83612607565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce006138468185614528565b6111588184614528565b6001600160a01b038381165f8181527fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259101612a07565b5f8281527f02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800602090815260408083206001600160a01b038516845290915290205460ff166112bf576040517fe2517d3f0000000000000000000000000000000000000000000000000000000081526001600160a01b038216600482015260248101839052604401611017565b6001600160a01b0381166112f5576040517f17858bbe0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611017565b6139a661407d565b7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce006139d18133614528565b6138468185614528565b6001600160a01b0382165f9081527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1026020526040902054818110156111ef576040517fdb42144d0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810182905260448101839052606401611017565b805f036112f5576040517f77b8dde300000000000000000000000000000000000000000000000000000000815260048101829052602401611017565b613aaa81614585565b6112bf82826145d4565b6001600160a01b0382165f8181527fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af10260209081526040808320805486900390557fee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af1008054869003815590518581529093917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101612a07565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff16612900576040517f8dfc202b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f613bb061115e565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b5f805f613c16868686614606565b90925090505f826005811115613c2e57613c2e61548e565b14613c39578161324b565b61324b878261464e565b5f816005811115613c5657613c5661548e565b03613c5e5750565b6001816005811115613c7257613c7261548e565b03613ca9576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6002816005811115613cbd57613cbd61548e565b03613cf4576040517f4be6321b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003816005811115613d0857613d0861548e565b03613d3f576040517fbf4bf5b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004816005811115613d5357613d5361548e565b03613d8a576040517fff551e8900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6005816005811115613d9e57613d9e61548e565b03613dd5576040517f10c74b0300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0382165f9081527f1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a48886006020908152604080832084845290915290205460ff16156112bf576040517fd309466d0000000000000000000000000000000000000000000000000000000081526001600160a01b038316600482015260248101829052604401611017565b5f805f613ea487878787614677565b90925090505f826005811115613ebc57613ebc61548e565b14613ec75781613ed1565b613ed1888261464e565b98975050505050505050565b613ee78482611414565b613f28576040517f74f091620000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611017565b611158838383614428565b6040516001600160a01b0384811660248301528381166044830152606482018390526111589186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050614777565b5f611058614018846001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547e01000000000000000000000000000000000000000000000000000000000000900460ff1690565b6006846147fc565b5f7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115614079576040517f2a49c10d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b7fcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f033005460ff1615612900576040517fd93c066500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6110586006614144856001600160a01b03165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547e01000000000000000000000000000000000000000000000000000000000000900460ff1690565b846147fc565b6001600160a01b0382165f9081527f4717d46f2e033163981fa31651301a35281b6b08316965d315fd1577bad94b0060205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16808211156111ef576040517f7c6781510000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810183905260448101829052606401611017565b6040516001600160a01b038381166024830152604482018390526111ef91859182169063a9059cbb90606401613f68565b5f805f6142358585614869565b90925090505f82600581111561424d5761424d61548e565b146142585781614262565b614262868261464e565b9695505050505050565b5f805f856001600160a01b0316858560405160240161428c9291906154bb565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1626ba7e000000000000000000000000000000000000000000000000000000001790525161430d91906154d3565b5f60405180830381855afa9150503d805f8114614345576040519150601f19603f3d011682016040523d82523d5f602084013e61434a565b606091505b509150915081801561435e57506020815110155b8015614262575080517f1626ba7e000000000000000000000000000000000000000000000000000000009061439c9083016020908101908401615387565b149695505050505050565b6143af6148ad565b612900576040517fd7e6bcf800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b804211156112f5576040517ff88f049000000000000000000000000000000000000000000000000000000000815260048101829052426024820152604401611017565b61381b61407d565b6144386143a7565b6112bf828260066148cb565b61444c6143a7565b6001600160a01b03811661448c576040517f6cbbd1d300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf7f109b88c1c8d528799ca6f455418979dd2a552493f14553ce44443b23f7df8b3582612607565b6144be6143a7565b6001600160a01b0381166144fe576040517f042d717b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6112bf7f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a82612607565b6001600160a01b0381165f9081526020839052604090205460ff16156112bf576040517f4f2a367e0000000000000000000000000000000000000000000000000000000081526001600160a01b0382166004820152602401611017565b5f61458e6123c3565b9050808211156112bf576040517f3dbc0a1b0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401611017565b6145dc61407d565b6112bf7f2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce0083614528565b5f80601b60ff84901c017f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841661463f87838884614677565b9350935050505b935093915050565b5f816001600160a01b0316836001600160a01b03161461466f576005611058565b505f92915050565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156146ac5750600390505f61476e565b8460ff16601b141580156146c457508460ff16601c14155b156146d45750600490505f61476e565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614724573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001519150506001600160a01b03811615614765575f81614769565b60015f5b915091505b94509492505050565b5f8060205f8451602086015f885af180614796576040513d5f823e3d81fd5b50505f513d915081156147ad5780600114156147ba565b6001600160a01b0384163b155b15611158576040517f5274afe70000000000000000000000000000000000000000000000000000000081526001600160a01b0385166004820152602401611017565b5f8260ff168460ff1603614811575080611058565b8260ff168460ff16116148425761482884846154e9565b61483390600a61561b565b61483d9083615629565b614861565b61484c83856154e9565b61485790600a61561b565b6148619083615640565b949350505050565b5f80825160411461487f5750600290505f6148a6565b6020830151604084015160608501515f1a919061489e87848484614677565b945094505050505b9250929050565b5f6148b6613382565b5468010000000000000000900460ff16919050565b6148d36143a7565b6148dc83614956565b7fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da101805460ff191660ff83161790557fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da1007fcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da102610f6184826156bc565b61495e6143a7565b6112f58161496a6143a7565b6112f5816149766143a7565b7f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea1007f103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea1026149c283826156bc565b504681556149ce6126d3565b60019091015550565b5f602082840312156149e7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611058575f80fd5b6001600160a01b03811681146112f5575f80fd5b803561137f81614a16565b5f60208284031215614a45575f80fd5b813561105881614a16565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6110586020830184614a50565b5f8060408385031215614abf575f80fd5b8235614aca81614a16565b946020939093013593505050565b5f60208284031215614ae8575f80fd5b5035919050565b5f8060208385031215614b00575f80fd5b823567ffffffffffffffff811115614b16575f80fd5b8301601f81018513614b26575f80fd5b803567ffffffffffffffff811115614b3c575f80fd5b8560208260051b8401011115614b50575f80fd5b6020919091019590945092505050565b5f805f60608486031215614b72575f80fd5b8335614b7d81614a16565b92506020840135614b8d81614a16565b929592945050506040919091013590565b5f8060408385031215614baf575f80fd5b823591506020830135614bc181614a16565b809150509250929050565b5f805f8060808587031215614bdf575f80fd5b8435614bea81614a16565b966020860135965060408601359560600135945092505050565b60ff811681146112f5575f80fd5b5f805f805f60a08688031215614c26575f80fd5b8535614c3181614a16565b9450602086013593506040860135614c4881614c04565b94979396509394606081013594506080013592915050565b7fff000000000000000000000000000000000000000000000000000000000000008816815260e060208201525f614c9a60e0830189614a50565b8281036040840152614cac8189614a50565b606084018890526001600160a01b038716608085015260a0840186905283810360c0850152845180825260208087019350909101905f5b81811015614d01578351835260209384019390920191600101614ce3565b50909b9a5050505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f82601f830112614d4e575f80fd5b8135602083015f8067ffffffffffffffff841115614d6e57614d6e614d12565b506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85018116603f0116810181811067ffffffffffffffff82111715614dbb57614dbb614d12565b604052838152905080828401871015614dd2575f80fd5b838360208301375f602085830101528094505050505092915050565b5f805f805f805f60e0888a031215614e04575f80fd5b8735614e0f81614a16565b96506020880135614e1f81614a16565b955060408801359450606088013593506080880135925060a0880135915060c088013567ffffffffffffffff811115614e56575f80fd5b614e628a828b01614d3f565b91505092959891949750929550565b5f805f805f805f80610100898b031215614e89575f80fd5b883567ffffffffffffffff811115614e9f575f80fd5b614eab8b828c01614d3f565b985050602089013567ffffffffffffffff811115614ec7575f80fd5b614ed38b828c01614d3f565b9750506040890135614ee481614a16565b95506060890135614ef481614a16565b94506080890135614f0481614a16565b935060a0890135614f1481614a16565b9250614f2260c08a01614a2a565b9150614f3060e08a01614a2a565b90509295985092959890939650565b5f805f805f60a08688031215614f53575f80fd5b8535614f5e81614a16565b94506020860135614f6e81614a16565b93506040860135925060608601359150608086013567ffffffffffffffff811115614f97575f80fd5b614fa388828901614d3f565b9150509295509295909350565b5f805f805f805f80610100898b031215614fc8575f80fd5b8835614fd381614a16565b97506020890135614fe381614a16565b979a9799505050506040860135956060810135956080820135955060a0820135945060c0820135935060e0909101359150565b5f805f60608486031215615028575f80fd5b833561503381614a16565b925060208401359150604084013567ffffffffffffffff811115615055575f80fd5b61506186828701614d3f565b9150509250925092565b5f805f805f805f60e0888a031215615081575f80fd5b873567ffffffffffffffff811115615097575f80fd5b6150a38a828b01614d3f565b975050602088013567ffffffffffffffff8111156150bf575f80fd5b6150cb8a828b01614d3f565b96505060408801356150dc81614a16565b945060608801356150ec81614a16565b935060808801356150fc81614a16565b925060a088013561510c81614a16565b915060c088013561511c81614a16565b8091505092959891949750929550565b5f805f805f805f60e0888a031215615142575f80fd5b873561514d81614a16565b9650602088013561515d81614a16565b95506040880135945060608801359350608088013561517b81614c04565b9699959850939692959460a0840135945060c09093013592915050565b5f80604083850312156151a9575f80fd5b82356151b481614a16565b91506020830135614bc181614a16565b5f805f805f805f805f6101208a8c0312156151dd575f80fd5b89356151e881614a16565b985060208a01356151f881614a16565b975060408a0135965060608a0135955060808a0135945060a08a0135935060c08a013561522481614c04565b989b979a50959894979396929550929360e081013593506101000135919050565b600181811c9082168061525957607f821691505b602082108103615290577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156152d3575f80fd5b81516fffffffffffffffffffffffffffffffff81168114611058575f80fd5b5f60208284031215615302575f80fd5b815161105881614a16565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b80820180821115610dea57610dea61530d565b5f6020828403121561535d575f80fd5b815161105881614c04565b5f60208284031215615378575f80fd5b81518015158114611058575f80fd5b5f60208284031215615397575f80fd5b5051919050565b5f8083546153ab81615245565b6001821680156153c257600181146153d757615404565b60ff1983168652811515820286019350615404565b865f5260205f205f5b838110156153fc578154888201526001909101906020016153e0565b505081860193505b509195945050505050565b81810381811115610dea57610dea61530d565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8181168382160190811115610dea57610dea61530d565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8281168282160390811115610dea57610dea61530d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f6148616040830184614a50565b5f82518060208501845e5f920191825250919050565b60ff8281168282160390811115610dea57610dea61530d565b6001815b6001841115614646578085048111156155215761552161530d565b600184161561552f57908102905b60019390931c928002615506565b5f8261554b57506001610dea565b8161555757505f610dea565b816001811461556d576002811461557757615593565b6001915050610dea565b60ff8411156155885761558861530d565b50506001821b610dea565b5060208310610133831016604e8410600b84101617156155b6575081810a610dea565b6155e17fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484615502565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156156135761561361530d565b029392505050565b5f61105860ff84168361553d565b8082028115828204841417610dea57610dea61530d565b5f82615673577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b601f8211156111ef57805f5260205f20601f840160051c8101602085101561569d5750805b601f840160051c820191505b81811015610f61575f81556001016156a9565b815167ffffffffffffffff8111156156d6576156d6614d12565b6156ea816156e48454615245565b84615678565b6020601f82116001811461573b575f83156157055750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455610f61565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b828110156157885787850151825560209485019460019092019101615768565b50848210156157c457868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b0190555056fea2646970667358221220add2fadee0a8f76e9df2259280327dc2ab1f1ef6fcde5a3f9accd646c8eddf9f64736f6c634300081a0033000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278","name":"JMIExtension","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"src/components/freezable/IFreezable.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.26;\n\n/**\n * @title Freezable interface.\n * @author M0 Labs\n */\ninterface IFreezable {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when an account is frozen.\n     * @param account The address of the frozen account.\n     * @param timestamp The timestamp at which the account was frozen.\n     */\n    event Frozen(address indexed account, uint256 timestamp);\n\n    /**\n     * @notice Emitted when an account is unfrozen.\n     * @param account The address of the unfrozen account.\n     * @param timestamp The timestamp at which the account was unfrozen.\n     */\n    event Unfrozen(address indexed account, uint256 timestamp);\n\n    /* ============ Errors ============ */\n\n    /**\n     * @notice Emitted when an account is already frozen.\n     * @param account The address of the frozen account.\n     */\n    error AccountFrozen(address account);\n\n    /**\n     * @notice Emitted when an account is not frozen.\n     * @param account The address of the account that is not frozen.\n     */\n    error AccountNotFrozen(address account);\n\n    /// @notice Emitted if no freeze manager is set.\n    error ZeroFreezeManager();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Freezes an account.\n     * @dev MUST only be callable by the FREEZE_MANAGER_ROLE.\n     * @param account The address of the account to freeze.\n     */\n    function freeze(address account) external;\n\n    /**\n     * @notice Freezes multiple accounts.\n     * @dev MUST only be callable by the FREEZE_MANAGER_ROLE.\n     * @param accounts The list of addresses to freeze.\n     */\n    function freezeAccounts(address[] calldata accounts) external;\n\n    /**\n     * @notice Unfreezes an account.\n     * @dev MUST only be callable by the FREEZE_MANAGER_ROLE.\n     * @param account The address of the account to unfreeze.\n     */\n    function unfreeze(address account) external;\n\n    /**\n     * @notice Unfreezes multiple accounts.\n     * @dev MUST only be callable by the FREEZE_MANAGER_ROLE.\n     * @param accounts The list of addresses to unfreeze.\n     */\n    function unfreezeAccounts(address[] calldata accounts) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The role that can manage the freezelist.\n    function FREEZE_MANAGER_ROLE() external view returns (bytes32);\n\n    /**\n     * @notice Returns whether an account is frozen or not.\n     * @param account The address of the account to check.\n     * @return True if the account is frozen, false otherwise.\n     */\n    function isFrozen(address account) external view returns (bool);\n}\n"},{"file_path":"lib/common/src/interfaces/IERC20Extended.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { IERC20 } from \"./IERC20.sol\";\nimport { IERC3009 } from \"./IERC3009.sol\";\n\n/**\n * @title  An ERC20 token extended with EIP-2612 permits for signed approvals (via EIP-712\n *         and with EIP-1271 compatibility), and extended with EIP-3009 transfer with authorization (via EIP-712).\n * @author M^0 Labs\n * @dev    The additional interface as defined by EIP-2612: https://eips.ethereum.org/EIPS/eip-2612\n */\ninterface IERC20Extended is IERC20, IERC3009 {\n    /* ============ Custom Errors ============ */\n\n    /**\n     * @notice Revert message when spender's allowance is not sufficient.\n     * @param  spender    Address that may be allowed to operate on tokens without being their owner.\n     * @param  allowance  Amount of tokens a `spender` is allowed to operate with.\n     * @param  needed     Minimum amount required to perform a transfer.\n     */\n    error InsufficientAllowance(address spender, uint256 allowance, uint256 needed);\n\n    /**\n     * @notice Revert message emitted when the transferred amount is insufficient.\n     * @param  amount Amount transferred.\n     */\n    error InsufficientAmount(uint256 amount);\n\n    /**\n     * @notice Revert message emitted when the recipient of a token is invalid.\n     * @param  recipient Address of the invalid recipient.\n     */\n    error InvalidRecipient(address recipient);\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Approves `spender` to spend up to `amount` of the token balance of `owner`, via a signature.\n     * @param  owner    The address of the account who's token balance is being approved to be spent by `spender`.\n     * @param  spender  The address of an account allowed to spend on behalf of `owner`.\n     * @param  value    The amount of the allowance being approved.\n     * @param  deadline The last timestamp where the signature is still valid.\n     * @param  v        An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  r        An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  s        An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @notice Approves `spender` to spend up to `amount` of the token balance of `owner`, via a signature.\n     * @param  owner     The address of the account who's token balance is being approved to be spent by `spender`.\n     * @param  spender   The address of an account allowed to spend on behalf of `owner`.\n     * @param  value     The amount of the allowance being approved.\n     * @param  deadline  The last timestamp where the signature is still valid.\n     * @param  signature An arbitrary signature (EIP-712).\n     */\n    function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice Returns the EIP712 typehash used in the encoding of the digest for the permit function.\n    function PERMIT_TYPEHASH() external view returns (bytes32);\n}\n"},{"file_path":"lib/common/src/StatefulERC712Upgradeable.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { IStatefulERC712 } from \"./interfaces/IStatefulERC712.sol\";\n\nimport { ERC712ExtendedUpgradeable } from \"./ERC712ExtendedUpgradeable.sol\";\n\nabstract contract StatefulERC712ExtendedUpgradeableStorageLayout {\n    /// @custom:storage-location erc7201:M0.storage.StatefulERC712Extended\n    struct StatefulERC712ExtendedStorageStruct {\n        mapping(address account => uint256 nonce) nonces; // Nonces for all signatures.\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.StatefulERC712Extended\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _STATEFUL_ERC712_EXTENDED_STORAGE_LOCATION =\n        0x1b21ba3f0a2135d61c468900b54084f04af8111bce0f8bbb6ab8c46d11afbd00;\n\n    function _getStatefulERC712ExtendedStorageLocation()\n        internal\n        pure\n        returns (StatefulERC712ExtendedStorageStruct storage $)\n    {\n        assembly {\n            $.slot := _STATEFUL_ERC712_EXTENDED_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title  Stateful and upgradeable extension for EIP-712 typed structured data hashing and signing with nonces.\n * @author M0 Labs\n * @dev    An abstract implementation to satisfy stateful EIP-712 with nonces.\n */\nabstract contract StatefulERC712Upgradeable is\n    StatefulERC712ExtendedUpgradeableStorageLayout,\n    IStatefulERC712,\n    ERC712ExtendedUpgradeable\n{\n    /* ============ Initializer ============ */\n\n    /**\n     * @notice Initializes the StatefulERC712Upgradeable contract.\n     * @param  name The name of the contract.\n     */\n    function __StatefulERC712ExtendedUpgradeable_init(string memory name) internal onlyInitializing {\n        __ERC712ExtendedUpgradeable_init(name);\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IStatefulERC712\n    function nonces(address account) external view returns (uint256) {\n        return _getStatefulERC712ExtendedStorageLocation().nonces[account];\n    }\n}\n"},{"file_path":"lib/common/src/interfaces/IERC712Extended.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { IERC712 } from \"./IERC712.sol\";\n\n/**\n * @title  EIP-712 extended by EIP-5267.\n * @author M^0 Labs\n * @dev    The additional interface as defined by EIP-5267: https://eips.ethereum.org/EIPS/eip-5267\n */\ninterface IERC712Extended is IERC712 {\n    /* ============ Events ============ */\n\n    /// @notice MAY be emitted to signal that the domain could have changed.\n    event EIP712DomainChanged();\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice Returns the fields and values that describe the domain separator used by this contract for EIP-712.\n    function eip712Domain()\n        external\n        view\n        returns (\n            bytes1 fields,\n            string memory name,\n            string memory version,\n            uint256 chainId,\n            address verifyingContract,\n            bytes32 salt,\n            uint256[] memory extensions\n        );\n}\n"},{"file_path":"src/projects/yieldToOne/interfaces/IMYieldToOne.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\n/**\n * @title M Extension where all yield is claimable by a single recipient.\n * @author M0 Labs\n */\ninterface IMYieldToOne {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when this contract's excess M is claimed.\n     * @param  yield The amount of M yield claimed.\n     */\n    event YieldClaimed(uint256 yield);\n\n    /**\n     * @notice Emitted when the yield recipient is set.\n     * @param  yieldRecipient The address of the new yield recipient.\n     */\n    event YieldRecipientSet(address indexed yieldRecipient);\n\n    /* ============ Custom Errors ============ */\n\n    /// @notice Emitted in initializer if Yield Recipient is 0x0.\n    error ZeroYieldRecipient();\n\n    /// @notice Emitted in initializer if Yield Recipient Manager is 0x0.\n    error ZeroYieldRecipientManager();\n\n    /// @notice Emitted in initializer if Admin is 0x0.\n    error ZeroAdmin();\n\n    /* ============ Interactive Functions ============ */\n\n    /// @notice Claims accrued yield to yield recipient.\n    function claimYield() external returns (uint256);\n\n    /**\n     * @notice Sets the yield recipient.\n     * @dev    MUST only be callable by the YIELD_RECIPIENT_MANAGER_ROLE.\n     * @dev    SHOULD revert if `yieldRecipient` is 0x0.\n     * @dev    SHOULD return early if the `yieldRecipient` is already the actual yield recipient.\n     * @param  yieldRecipient The address of the new yield recipient.\n     */\n    function setYieldRecipient(address yieldRecipient) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The role that can manage the yield recipient.\n    function YIELD_RECIPIENT_MANAGER_ROLE() external view returns (bytes32);\n\n    /// @notice The amount of accrued yield.\n    function yield() external view returns (uint256);\n\n    /// @notice The address of the yield recipient.\n    function yieldRecipient() external view returns (address);\n}\n"},{"file_path":"src/swap/interfaces/ISwapFacility.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\n/**\n * @title  Swap Facility interface.\n * @author M0 Labs\n */\ninterface ISwapFacility {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when $M Extension is swapped for another $M Extension.\n     * @param extensionIn  The address of the input $M Extension.\n     * @param extensionOut The address of the output $M Extension.\n     * @param amount       The amount swapped.\n     * @param recipient    The address to receive the output $M Extension token.\n     */\n    event Swapped(address indexed extensionIn, address indexed extensionOut, uint256 amount, address indexed recipient);\n\n    /**\n     * @notice Emitted when $M token is swapped for $M Extension.\n     * @param extensionOut The address of the output $M Extension.\n     * @param amount       The amount swapped.\n     * @param recipient    The address to receive the output $M Extension token.\n     */\n    event SwappedInM(address indexed extensionOut, uint256 amount, address indexed recipient);\n\n    /**\n     * @notice Emitted when $M Extension is swapped for $M token.\n     * @param extensionIn  The address of the input $M Extension.\n     * @param amount       The amount swapped.\n     * @param recipient    The address to receive the $M token.\n     */\n    event SwappedOutM(address indexed extensionIn, uint256 amount, address indexed recipient);\n\n    /**\n     * @notice Emitted when an $M Extension is set as permissioned or not.\n     * @param  extension The address of an $M Extension.\n     * @param  allowed   True if the extension is allowed, false otherwise.\n     */\n    event PermissionedExtensionSet(address indexed extension, bool allowed);\n\n    /**\n     * @notice Emitted when a `swapper` is allowed or not to swap the permissioned `extension` from/to M.\n     * @param  extension The address of an $M extension.\n     * @param  swapper   The address of the swapper.\n     * @param  allowed   True if the swapper is allowed, false otherwise.\n     */\n    event PermissionedMSwapperSet(address indexed extension, address indexed swapper, bool allowed);\n\n    /**\n     * @notice Emitted when an $M Extension is admin approved or not.\n     * @param  extension The address of an $M Extension.\n     * @param  approved   True if the extension is approved, false otherwise.\n     */\n    event AdminApprovedExtensionSet(address indexed extension, bool approved);\n\n    /**\n     * @notice Emitted when $M token is swapped for JMI Extension.\n     * @param  asset        The address of the asset.\n     * @param  extensionOut The address of the JMI Extension.\n     * @param  amount       The amount swapped.\n     * @param  recipient    The address to receive the JMI Extension tokens.\n     */\n    event SwappedInJMI(address indexed asset, address indexed extensionOut, uint256 amount, address indexed recipient);\n\n    /**\n     * @notice Emitted when `asset` is replaced with $M for a JMI Extension.\n     * @param  asset        The address of an asset.\n     * @param  extensionOut The address of a JMI Extension.\n     * @param  amount       The amount of $M tokens deposited to replace `asset`.\n     */\n    event JMIAssetReplaced(address indexed asset, address indexed extensionOut, uint256 amount);\n\n    /* ============ Custom Errors ============ */\n\n    /// @notice Thrown in the constructor if $M Token is 0x0.\n    error ZeroMToken();\n\n    /// @notice Thrown in the constructor if Registrar is 0x0.\n    error ZeroRegistrar();\n\n    /// @notice Thrown in `setPermissionedMSwapper()` if the $M extension is 0x0.\n    error ZeroExtension();\n\n    /// @notice Thrown in `setPermissionedMSwapper()` if the swapper is 0x0.\n    error ZeroSwapper();\n\n    /// @notice Thrown in `swap` functions if an extension is not a TTG approved earner.\n    error NotApprovedExtension(address extension);\n\n    /// @notice Thrown in `swap` if `swapper` is not approved to swap a permissioned `extension`.\n    error NotApprovedPermissionedSwapper(address extension, address swapper);\n\n    /// @notice Thrown in `swap` if `swapper` is not approved to swap the `extension`.\n    error NotApprovedSwapper(address extension, address swapper);\n\n    /// @notice Thrown in `swap` function if an extension is permissioned.\n    error PermissionedExtension(address extension);\n\n    /// @notice Thrown in `swap` function if the provided tokens do not represent a valid swap path.\n    error InvalidSwapPath(address tokenIn, address tokenOut);\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Swaps between two tokens, which can be $M, $M Extensions, or an asset used by JMI Extensions.\n     * @param  tokenIn      The address of the token to swap from.\n     * @param  tokenOut     The address of the token to swap to.\n     * @param  amount       The amount to swap.\n     * @param  recipient    The address to receive the swapped tokens.\n     */\n    function swap(address tokenIn, address tokenOut, uint256 amount, address recipient) external;\n\n    /**\n     * @notice Swaps between two tokens using permit.\n     * @param  tokenIn      The address of the token to swap from.\n     * @param  tokenOut     The address of the token to swap to.\n     * @param  amount       The amount to swap.\n     * @param  recipient    The address to receive the swapped tokens.\n     * @param  deadline     The last timestamp where the signature is still valid.\n     * @param  v            An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  r            An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  s            An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     */\n    function swapWithPermit(\n        address tokenIn,\n        address tokenOut,\n        uint256 amount,\n        address recipient,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @notice Swaps between two tokens using permit.\n     * @param  tokenIn      The address of the token to swap from.\n     * @param  tokenOut     The address of the token to swap to.\n     * @param  amount       The amount to swap.\n     * @param  recipient    The address to receive the swapped tokens.\n     * @param  deadline     The last timestamp where the signature is still valid.\n     * @param  signature    An arbitrary signature (EIP-712).\n     */\n    function swapWithPermit(\n        address tokenIn,\n        address tokenOut,\n        uint256 amount,\n        address recipient,\n        uint256 deadline,\n        bytes calldata signature\n    ) external;\n\n    /**\n     * @notice Swaps $M token to $M Extension.\n     * @param  extensionOut The address of the M Extension to swap to.\n     * @param  amount       The amount of $M token to swap.\n     * @param  recipient    The address to receive the swapped $M Extension tokens.\n     */\n    function swapInM(address extensionOut, uint256 amount, address recipient) external;\n\n    /**\n     * @notice Swaps $M Extension to $M token.\n     * @param  extensionIn The address of the $M Extension to swap from.\n     * @param  amount      The amount of $M Extension tokens to swap.\n     * @param  recipient   The address to receive $M tokens.\n     */\n    function swapOutM(address extensionIn, uint256 amount, address recipient) external;\n\n    /**\n     * @notice Replaces `amount` of `asset` held in a JMI Extension with $M.\n     * @param  asset        The address of the asset.\n     * @param  extensionIn  The address of an $M extension to unwrap $M from and replace `asset` with.\n     * @param  extensionOut The address of a JMI Extension.\n     * @param  amount       The amount of $M to replace.\n     * @param  recipient    The address to receive `amount` of `asset` tokens.\n     */\n    function replaceAssetWithM(\n        address asset,\n        address extensionIn,\n        address extensionOut,\n        uint256 amount,\n        address recipient\n    ) external;\n\n    /**\n     * @notice Replaces `amount` of `asset` held in a JMI Extension with $M using permit.\n     * @param  asset        The address of the asset.\n     * @param  extensionIn  The address of an $M extension to unwrap $M from and replace `asset` with.\n     * @param  extensionOut The address of a JMI Extension.\n     * @param  amount       The amount of $M to replace.\n     * @param  recipient    The address to receive `amount` of `asset` tokens.\n     * @param  deadline     The last timestamp where the signature is still valid.\n     * @param  v            An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  r            An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  s            An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     */\n    function replaceAssetWithMWithPermit(\n        address asset,\n        address extensionIn,\n        address extensionOut,\n        uint256 amount,\n        address recipient,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @notice Replaces `amount` of `asset` held in a JMI Extension with $M using permit.\n     * @param  asset        The address of the asset.\n     * @param  extensionIn  The address of an $M extension to unwrap $M from and replace `asset` with.\n     * @param  extensionOut The address of a JMI Extension.\n     * @param  amount       The amount of $M to replace.\n     * @param  recipient    The address to receive `amount` of `asset` tokens.\n     * @param  deadline     The last timestamp where the signature is still valid.\n     * @param  signature    An arbitrary signature (EIP-712).\n     */\n    function replaceAssetWithMWithPermit(\n        address asset,\n        address extensionIn,\n        address extensionOut,\n        uint256 amount,\n        address recipient,\n        uint256 deadline,\n        bytes calldata signature\n    ) external;\n\n    /**\n     * @notice Sets whether the `extension` is permissioned.\n     * @dev    MUST only be callable by an address with the `DEFAULT_ADMIN_ROLE` role.\n     * @param  extension    The address of an $M Extension.\n     * @param  permissioned True if the extension is permissioned, false otherwise.\n     */\n    function setPermissionedExtension(address extension, bool permissioned) external;\n\n    /**\n     * @notice Sets whether `swapper` is allowed to swap the permissioned `extension` from/to M.\n     * @dev    MUST only be callable by an address with the `DEFAULT_ADMIN_ROLE` role.\n     * @param  extension The address of an extension to set permission for.\n     * @param  swapper   The address of the swapper to set permission for.\n     * @param  allowed   True if the swapper is allowed, false otherwise.\n     */\n    function setPermissionedMSwapper(address extension, address swapper, bool allowed) external;\n\n    /**\n     * @notice Sets whether the `extension` is admin approved.\n     * @dev    MUST only be callable by an address with the `DEFAULT_ADMIN_ROLE` role.\n     * @param  extension    The address of an $M Extension.\n     * @param  approved True if the extension is admin approved, false otherwise.\n     */\n    function setAdminApprovedExtension(address extension, bool approved) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The address of the $M Token contract.\n    function mToken() external view returns (address);\n\n    /// @notice The address of the Registrar.\n    function registrar() external view returns (address);\n\n    /**\n     * @notice Returns the address that called `swap` or `swapM`\n     * @dev    Must be used instead of `msg.sender` in $M Extensions contracts to get the original sender.\n     */\n    function msgSender() external view returns (address);\n\n    /**\n     * @notice Checks if the extension is permissioned.\n     * @param  extension The extension address to check.\n     * @return true if allowed, false otherwise.\n     */\n    function isPermissionedExtension(address extension) external view returns (bool);\n\n    /**\n     * @notice Checks if `swapper` is allowed to swap the permissioned extension from/to M.\n     * @param  extension The $M extension address.\n     * @param  swapper   The swapper address to check.\n     * @return true if allowed, false otherwise.\n     */\n    function isPermissionedMSwapper(address extension, address swapper) external view returns (bool);\n\n    /**\n     * @notice Checks if `swapper` is allowed to swap the permissionless (common) extension from/to M.\n     * @param  swapper   The swapper address to check.\n     * @return true if allowed, false otherwise.\n     */\n    function isMSwapper(address swapper) external view returns (bool);\n\n    /**\n     * @notice Checks if the extension is admin approved.\n     * @param  extension The extension address to check.\n     * @return true if approved, false otherwise.\n     */\n    function isAdminApprovedExtension(address extension) external view returns (bool);\n\n    /**\n     * @notice Checks if the extension is approved (either as an earner or admin approved).\n     * @param  extension The extension address to check.\n     * @return true if approved, false otherwise.\n     */\n    function isApprovedExtension(address extension) external view returns (bool);\n\n    /**\n     * @notice Checks if `swapper` can swap between `tokenIn` and `tokenOut`.\n     * @param  swapper   The address of the swapper.\n     * @param  tokenIn   The address of the input token.\n     * @param  tokenOut  The address of the output token.\n     * @return true if can swap, false otherwise.\n     */\n    function canSwapViaPath(address swapper, address tokenIn, address tokenOut) external view returns (bool);\n\n    /// @notice The parameter name in the Registrar that defines the earners list.\n    function EARNERS_LIST_NAME() external pure returns (bytes32);\n\n    /// @notice The parameter name in the Registrar that defines whether to ignore the earners list.\n    function EARNERS_LIST_IGNORED_KEY() external pure returns (bytes32);\n\n    /// @notice Swapper role for permissioned extensions.\n    function M_SWAPPER_ROLE() external pure returns (bytes32);\n}\n"},{"file_path":"src/interfaces/IMTokenLike.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\n/**\n * @title  Subset of M Token interface required for source contracts.\n * @author M0 Labs\n */\ninterface IMTokenLike {\n    /* ============ Custom Errors ============ */\n\n    /// @notice Emitted when calling `stopEarning` for an account approved as earner by TTG.\n    error IsApprovedEarner();\n\n    /// @notice Emitted when calling `startEarning` for an account not approved as earner by TTG.\n    error NotApprovedEarner();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Allows a calling account to approve `spender` to spend up to `amount` of its token balance.\n     * @dev    MUST emit an `Approval` event.\n     * @param  spender The address of the account being allowed to spend up to the allowed amount.\n     * @param  amount  The amount of the allowance being approved.\n     * @return Whether or not the approval was successful.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @notice Approves `spender` to spend up to `amount` of the token balance of `owner`, via a signature.\n     * @param  owner    The address of the account who's token balance is being approved to be spent by `spender`.\n     * @param  spender  The address of an account allowed to spend on behalf of `owner`.\n     * @param  value    The amount of the allowance being approved.\n     * @param  deadline The last timestamp where the signature is still valid.\n     * @param  v        An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  r        An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     * @param  s        An ECDSA secp256k1 signature parameter (EIP-2612 via EIP-712).\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @notice Approves `spender` to spend up to `amount` of the token balance of `owner`, via a signature.\n     * @param  owner     The address of the account who's token balance is being approved to be spent by `spender`.\n     * @param  spender   The address of an account allowed to spend on behalf of `owner`.\n     * @param  value     The amount of the allowance being approved.\n     * @param  deadline  The last timestamp where the signature is still valid.\n     * @param  signature An arbitrary signature (EIP-712).\n     */\n    function permit(address owner, address spender, uint256 value, uint256 deadline, bytes memory signature) external;\n\n    /**\n     * @notice Allows a calling account to transfer `amount` tokens to `recipient`.\n     * @param  recipient The address of the recipient who's token balance will be incremented.\n     * @param  amount    The amount of tokens being transferred.\n     * @return success   Whether or not the transfer was successful.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @notice Allows a calling account to transfer `amount` tokens from `sender`, with allowance, to a `recipient`.\n     * @param  sender    The address of the sender who's token balance will be decremented.\n     * @param  recipient The address of the recipient who's token balance will be incremented.\n     * @param  amount    The amount of tokens being transferred.\n     * @return success   Whether or not the transfer was successful.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /// @notice Starts earning for caller if allowed by the Registrar.\n    function startEarning() external;\n\n    /**\n     * @notice Stops earning for `account`.\n     * @dev    MUST revert if `account` is an approved earner in TTG Registrar.\n     * @param  account The account to stop earning for.\n     */\n    function stopEarning(address account) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /**\n     * @notice Checks if account is an earner.\n     * @param  account The account to check.\n     * @return earning True if account is an earner, false otherwise.\n     */\n    function isEarning(address account) external view returns (bool);\n\n    /**\n     * @notice Returns the token balance of `account`.\n     * @param  account The address of some account.\n     * @return balance The token balance of `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @notice Returns the token balance of `account`.\n     * @param  account The address of some account.\n     * @return principal The principal token balance of `account`.\n     */\n    function principalBalanceOf(address account) external view returns (uint240);\n\n    /// @notice The current index that would be written to storage if `updateIndex` is called.\n    function currentIndex() external view returns (uint128);\n\n    /// @notice The current value of earner rate in basis points.\n    function earnerRate() external view returns (uint32);\n\n    /// @notice Returns the EIP712 domain separator used in the encoding of a signed digest.\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n\n    /// @notice Returns the EIP712 typehash used in the encoding of the digest for the permit function.\n    function PERMIT_TYPEHASH() external view returns (bytes32);\n\n    /// @notice Updates the index and returns it.\n    function updateIndex() external returns (uint128);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC-20 standard.\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"lib/common/src/interfaces/IStatefulERC712.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { IERC712Extended } from \"./IERC712Extended.sol\";\n\n/**\n * @title  Stateful Extension for EIP-712 typed structured data hashing and signing with nonces.\n * @author M^0 Labs\n */\ninterface IStatefulERC712 is IERC712Extended {\n    /* ============ Custom Errors ============ */\n\n    /**\n     * @notice Revert message when a signing account's nonce is not the expected current nonce.\n     * @param  nonce         The nonce used in the signature.\n     * @param  expectedNonce The expected nonce to be used in a signature by the signing account.\n     */\n    error InvalidAccountNonce(uint256 nonce, uint256 expectedNonce);\n\n    /* ============ View/Pure Functions ============ */\n\n    /**\n     * @notice Returns the next nonce to be used in a signature by `account`.\n     * @param  account The address of some account.\n     * @return nonce   The next nonce to be used in a signature by `account`.\n     */\n    function nonces(address account) external view returns (uint256 nonce);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"},{"file_path":"src/components/pausable/IPausable.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.26;\n\n/**\n * @title Pausable interface.\n * @author M0 Labs\n */\ninterface IPausable {\n    /* ============ Errors ============ */\n\n    /// @notice Emitted if no pauser is set.\n    error ZeroPauser();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Pauses the contract.\n     * @dev    Can only be called by an account with the PAUSER_ROLE.\n     * @dev    When paused, wrap/unwrap and transfer of tokens should be disabled.\n     *         Approval should still be enabled to allow users to change their allowances.\n     */\n    function pause() external;\n\n    /**\n     * @notice Unpauses the contract.\n     * @dev    Can only be called by an account with the PAUSER_ROLE.\n     */\n    function unpause() external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The role that can pause/unpause the contract.\n    function PAUSER_ROLE() external view returns (bytes32);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reinitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n     *\n     * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n     */\n    function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n        return INITIALIZABLE_STORAGE;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        bytes32 slot = _initializableStorageSlot();\n        assembly {\n            $.slot := slot\n        }\n    }\n}\n"},{"file_path":"lib/common/src/libs/SignatureChecker.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { IERC1271 } from \"../interfaces/IERC1271.sol\";\n\n/**\n * @title  A library to handle ECDSA/secp256k1 and ERC1271 signatures, individually or in arbitrarily in combination.\n * @author M^0 Labs\n */\nlibrary SignatureChecker {\n    /* ============ Enums ============ */\n\n    /**\n     * @notice An enum representing the possible errors that can be emitted during signature validation.\n     * @param  NoError                No error occurred during signature validation.\n     * @param  InvalidSignature       The signature is invalid.\n     * @param  InvalidSignatureLength The signature length is invalid.\n     * @param  InvalidSignatureS      The signature parameter S is invalid.\n     * @param  InvalidSignatureV      The signature parameter V is invalid.\n     * @param  SignerMismatch         The signer does not match the recovered signer.\n     */\n    enum Error {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV,\n        SignerMismatch\n    }\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @dev    Returns whether a signature is valid (ECDSA/secp256k1 or ERC1271) for a signer and digest.\n     * @dev    Signatures must not be used as unique identifiers since the `ecrecover` EVM opcode\n     *         allows for malleable (non-unique) signatures.\n     *         See https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-4h98-2769-gh6h\n     * @param  signer    The address of the account purported to have signed.\n     * @param  digest    The hash of the data that was signed.\n     * @param  signature A byte array signature.\n     * @return           Whether the signature is valid or not.\n     */\n    function isValidSignature(address signer, bytes32 digest, bytes memory signature) internal view returns (bool) {\n        return isValidECDSASignature(signer, digest, signature) || isValidERC1271Signature(signer, digest, signature);\n    }\n\n    /**\n     * @dev    Returns whether an ERC1271 signature is valid for a signer and digest.\n     * @param  signer    The address of the account purported to have signed.\n     * @param  digest    The hash of the data that was signed.\n     * @param  signature A byte array ERC1271 signature.\n     * @return           Whether the signature is valid or not.\n     */\n    function isValidERC1271Signature(\n        address signer,\n        bytes32 digest,\n        bytes memory signature\n    ) internal view returns (bool) {\n        (bool success_, bytes memory result_) = signer.staticcall(\n            abi.encodeCall(IERC1271.isValidSignature, (digest, signature))\n        );\n\n        return\n            success_ &&\n            result_.length >= 32 &&\n            abi.decode(result_, (bytes32)) == bytes32(IERC1271.isValidSignature.selector);\n    }\n\n    /**\n     * @dev    Decodes an ECDSA/secp256k1 signature from a byte array to standard v, r, and s parameters.\n     * @param  signature A byte array ECDSA/secp256k1 signature.\n     * @return v         An ECDSA/secp256k1 signature parameter.\n     * @return r         An ECDSA/secp256k1 signature parameter.\n     * @return s         An ECDSA/secp256k1 signature parameter.\n     */\n    function decodeECDSASignature(bytes memory signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {\n        // ecrecover takes the signature parameters, and they can be decoded using assembly.\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := mload(add(signature, 0x20))\n            s := mload(add(signature, 0x40))\n            v := byte(0, mload(add(signature, 0x60)))\n        }\n    }\n\n    /**\n     * @dev    Decodes an ECDSA/secp256k1 short signature as defined by EIP2098\n     *         from a byte array to standard v, r, and s parameters.\n     * @param  signature A byte array ECDSA/secp256k1 short signature.\n     * @return r         An ECDSA/secp256k1 signature parameter.\n     * @return vs        An ECDSA/secp256k1 short signature parameter.\n     */\n    function decodeShortECDSASignature(bytes memory signature) internal pure returns (bytes32 r, bytes32 vs) {\n        // ecrecover takes the signature parameters, and they can be decoded using assembly.\n        /// @solidity memory-safe-assembly\n        assembly {\n            r := mload(add(signature, 0x20))\n            vs := mload(add(signature, 0x40))\n        }\n    }\n\n    /**\n     * @dev    Returns whether an ECDSA/secp256k1 signature is valid for a signer and digest.\n     * @param  signer    The address of the account purported to have signed.\n     * @param  digest    The hash of the data that was signed.\n     * @param  signature A byte array ECDSA/secp256k1 signature (encoded r, s, v).\n     * @return           Whether the signature is valid or not.\n     */\n    function isValidECDSASignature(\n        address signer,\n        bytes32 digest,\n        bytes memory signature\n    ) internal pure returns (bool) {\n        if (signature.length == 64) {\n            (bytes32 r, bytes32 vs) = decodeShortECDSASignature(signature);\n            return isValidECDSASignature(signer, digest, r, vs);\n        }\n\n        return validateECDSASignature(signer, digest, signature) == Error.NoError;\n    }\n\n    /**\n     * @dev    Returns whether an ECDSA/secp256k1 short signature is valid for a signer and digest.\n     * @param  signer The address of the account purported to have signed.\n     * @param  digest The hash of the data that was signed.\n     * @param  r      An ECDSA/secp256k1 signature parameter.\n     * @param  vs     An ECDSA/secp256k1 short signature parameter.\n     * @return        Whether the signature is valid or not.\n     */\n    function isValidECDSASignature(address signer, bytes32 digest, bytes32 r, bytes32 vs) internal pure returns (bool) {\n        return validateECDSASignature(signer, digest, r, vs) == Error.NoError;\n    }\n\n    /**\n     * @dev    Returns the signer of an ECDSA/secp256k1 signature for some digest.\n     * @param  digest    The hash of the data that was signed.\n     * @param  signature A byte array ECDSA/secp256k1 signature.\n     * @return           An error, if any, that occurred during the signer recovery.\n     * @return           The address of the account recovered form the signature (0 if error).\n     */\n    function recoverECDSASigner(bytes32 digest, bytes memory signature) internal pure returns (Error, address) {\n        if (signature.length != 65) return (Error.InvalidSignatureLength, address(0));\n\n        (uint8 v, bytes32 r, bytes32 s) = decodeECDSASignature(signature);\n\n        return recoverECDSASigner(digest, v, r, s);\n    }\n\n    /**\n     * @dev    Returns the signer of an ECDSA/secp256k1 short signature for some digest.\n     * @dev    See https://eips.ethereum.org/EIPS/eip-2098\n     * @param  digest The hash of the data that was signed.\n     * @param  r      An ECDSA/secp256k1 signature parameter.\n     * @param  vs     An ECDSA/secp256k1 short signature parameter.\n     * @return        An error, if any, that occurred during the signer recovery.\n     * @return        The address of the account recovered form the signature (0 if error).\n     */\n    function recoverECDSASigner(bytes32 digest, bytes32 r, bytes32 vs) internal pure returns (Error, address) {\n        unchecked {\n            // We do not check for an overflow here since the shift operation results in 0 or 1.\n            uint8 v = uint8((uint256(vs) >> 255) + 27);\n            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n            return recoverECDSASigner(digest, v, r, s);\n        }\n    }\n\n    /**\n     * @dev    Returns the signer of an ECDSA/secp256k1 signature for some digest.\n     * @param  digest The hash of the data that was signed.\n     * @param  v      An ECDSA/secp256k1 signature parameter.\n     * @param  r      An ECDSA/secp256k1 signature parameter.\n     * @param  s      An ECDSA/secp256k1 signature parameter.\n     * @return        An error, if any, that occurred during the signer recovery.\n     * @return signer The address of the account recovered form the signature (0 if error).\n     */\n    function recoverECDSASigner(\n        bytes32 digest,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (Error, address signer) {\n        // Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}.\n        if (uint256(s) > uint256(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0))\n            return (Error.InvalidSignatureS, address(0));\n\n        if (v != 27 && v != 28) return (Error.InvalidSignatureV, address(0));\n\n        signer = ecrecover(digest, v, r, s);\n\n        return (signer == address(0)) ? (Error.InvalidSignature, address(0)) : (Error.NoError, signer);\n    }\n\n    /**\n     * @dev    Returns an error, if any, in validating an ECDSA/secp256k1 signature for a signer and digest.\n     * @param  signer    The address of the account purported to have signed.\n     * @param  digest    The hash of the data that was signed.\n     * @param  signature A byte array ERC1271 signature.\n     * @return           An error, if any, that occurred during the signer recovery.\n     */\n    function validateECDSASignature(\n        address signer,\n        bytes32 digest,\n        bytes memory signature\n    ) internal pure returns (Error) {\n        (Error recoverError, address recoveredSigner) = recoverECDSASigner(digest, signature);\n\n        return (recoverError == Error.NoError) ? validateRecoveredSigner(signer, recoveredSigner) : recoverError;\n    }\n\n    /**\n     * @dev    Returns an error, if any, in validating an ECDSA/secp256k1 short signature for a signer and digest.\n     * @param  signer The address of the account purported to have signed.\n     * @param  digest The hash of the data that was signed.\n     * @param  r      An ECDSA/secp256k1 signature parameter.\n     * @param  vs     An ECDSA/secp256k1 short signature parameter.\n     * @return        An error, if any, that occurred during the signer recovery.\n     */\n    function validateECDSASignature(\n        address signer,\n        bytes32 digest,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (Error) {\n        (Error recoverError, address recoveredSigner) = recoverECDSASigner(digest, r, vs);\n\n        return (recoverError == Error.NoError) ? validateRecoveredSigner(signer, recoveredSigner) : recoverError;\n    }\n\n    /**\n     * @dev    Returns an error, if any, in validating an ECDSA/secp256k1 signature for a signer and digest.\n     * @param  signer The address of the account purported to have signed.\n     * @param  digest The hash of the data that was signed.\n     * @param  v      An ECDSA/secp256k1 signature parameter.\n     * @param  r      An ECDSA/secp256k1 signature parameter.\n     * @param  s      An ECDSA/secp256k1 signature parameter.\n     * @return        An error, if any, that occurred during the signer recovery.\n     */\n    function validateECDSASignature(\n        address signer,\n        bytes32 digest,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (Error) {\n        (Error recoverError, address recoveredSigner) = recoverECDSASigner(digest, v, r, s);\n\n        return (recoverError == Error.NoError) ? validateRecoveredSigner(signer, recoveredSigner) : recoverError;\n    }\n\n    /**\n     * @dev    Returns an error if `signer` is not `recoveredSigner`.\n     * @param  signer          The address of the some signer.\n     * @param  recoveredSigner The address of the some recoveredSigner.\n     * @return                 An error if `signer` is not `recoveredSigner`.\n     */\n    function validateRecoveredSigner(address signer, address recoveredSigner) internal pure returns (Error) {\n        return (signer == recoveredSigner) ? Error.NoError : Error.SignerMismatch;\n    }\n}\n"},{"file_path":"lib/common/src/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\n/**\n * @title  ERC20 Token Standard.\n * @author M^0 Labs\n * @dev    The interface as defined by EIP-20: https://eips.ethereum.org/EIPS/eip-20\n */\ninterface IERC20 {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when `spender` has been approved for `amount` of the token balance of `account`.\n     * @param  account The address of the account.\n     * @param  spender The address of the spender being approved for the allowance.\n     * @param  amount  The amount of the allowance being approved.\n     */\n    event Approval(address indexed account, address indexed spender, uint256 amount);\n\n    /**\n     * @notice Emitted when `amount` tokens is transferred from `sender` to `recipient`.\n     * @param  sender    The address of the sender who's token balance is decremented.\n     * @param  recipient The address of the recipient who's token balance is incremented.\n     * @param  amount    The amount of tokens being transferred.\n     */\n    event Transfer(address indexed sender, address indexed recipient, uint256 amount);\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Allows a calling account to approve `spender` to spend up to `amount` of its token balance.\n     * @dev    MUST emit an `Approval` event.\n     * @param  spender The address of the account being allowed to spend up to the allowed amount.\n     * @param  amount  The amount of the allowance being approved.\n     * @return Whether or not the approval was successful.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @notice Allows a calling account to transfer `amount` tokens to `recipient`.\n     * @param  recipient The address of the recipient who's token balance will be incremented.\n     * @param  amount    The amount of tokens being transferred.\n     * @return Whether or not the transfer was successful.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @notice Allows a calling account to transfer `amount` tokens from `sender`, with allowance, to a `recipient`.\n     * @param  sender    The address of the sender who's token balance will be decremented.\n     * @param  recipient The address of the recipient who's token balance will be incremented.\n     * @param  amount    The amount of tokens being transferred.\n     * @return Whether or not the transfer was successful.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /* ============ View/Pure Functions ============ */\n\n    /**\n     * @notice Returns the allowance `spender` is allowed to spend on behalf of `account`.\n     * @param  account The address of the account who's token balance `spender` is allowed to spend.\n     * @param  spender The address of an account allowed to spend on behalf of `account`.\n     * @return The amount `spender` can spend on behalf of `account`.\n     */\n    function allowance(address account, address spender) external view returns (uint256);\n\n    /**\n     * @notice Returns the token balance of `account`.\n     * @param  account The address of some account.\n     * @return The token balance of `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /// @notice Returns the number of decimals UIs should assume all amounts have.\n    function decimals() external view returns (uint8);\n\n    /// @notice Returns the name of the contract/token.\n    function name() external view returns (string memory);\n\n    /// @notice Returns the symbol of the token.\n    function symbol() external view returns (string memory);\n\n    /// @notice Returns the current total supply of the token.\n    function totalSupply() external view returns (uint256);\n}\n"},{"file_path":"lib/common/src/libs/UIntMath.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\n/**\n * @title  Library to perform safe math operations on uint types\n * @author M^0 Labs\n */\nlibrary UIntMath {\n    /* ============ Custom Errors ============ */\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint16.\n    error InvalidUInt16();\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint32.\n    error InvalidUInt32();\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint40.\n    error InvalidUInt40();\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint48.\n    error InvalidUInt48();\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint112.\n    error InvalidUInt112();\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint128.\n    error InvalidUInt128();\n\n    /// @notice Emitted when a passed value is greater than the maximum value of uint240.\n    error InvalidUInt240();\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @notice Casts a uint256 value to a uint16, ensuring that it is less than or equal to the maximum uint16 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint16.\n     */\n    function safe16(uint256 n) internal pure returns (uint16) {\n        if (n > type(uint16).max) revert InvalidUInt16();\n        return uint16(n);\n    }\n\n    /**\n     * @notice Casts a uint256 value to a uint32, ensuring that it is less than or equal to the maximum uint32 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint32.\n     */\n    function safe32(uint256 n) internal pure returns (uint32) {\n        if (n > type(uint32).max) revert InvalidUInt32();\n        return uint32(n);\n    }\n\n    /**\n     * @notice Casts a uint256 value to a uint40, ensuring that it is less than or equal to the maximum uint40 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint40.\n     */\n    function safe40(uint256 n) internal pure returns (uint40) {\n        if (n > type(uint40).max) revert InvalidUInt40();\n        return uint40(n);\n    }\n\n    /**\n     * @notice Casts a uint256 value to a uint48, ensuring that it is less than or equal to the maximum uint48 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint48.\n     */\n    function safe48(uint256 n) internal pure returns (uint48) {\n        if (n > type(uint48).max) revert InvalidUInt48();\n        return uint48(n);\n    }\n\n    /**\n     * @notice Casts a uint256 value to a uint112, ensuring that it is less than or equal to the maximum uint112 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint112.\n     */\n    function safe112(uint256 n) internal pure returns (uint112) {\n        if (n > type(uint112).max) revert InvalidUInt112();\n        return uint112(n);\n    }\n\n    /**\n     * @notice Casts a uint256 value to a uint128, ensuring that it is less than or equal to the maximum uint128 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint128.\n     */\n    function safe128(uint256 n) internal pure returns (uint128) {\n        if (n > type(uint128).max) revert InvalidUInt128();\n        return uint128(n);\n    }\n\n    /**\n     * @notice Casts a uint256 value to a uint240, ensuring that it is less than or equal to the maximum uint240 value.\n     * @param  n The value to cast.\n     * @return The value casted to uint240.\n     */\n    function safe240(uint256 n) internal pure returns (uint240) {\n        if (n > type(uint240).max) revert InvalidUInt240();\n        return uint240(n);\n    }\n\n    /**\n     * @notice Limits a uint256 value to the maximum uint32 value.\n     * @param  n The value to bound.\n     * @return The value limited to within uint32 bounds.\n     */\n    function bound32(uint256 n) internal pure returns (uint32) {\n        return uint32(min256(n, uint256(type(uint32).max)));\n    }\n\n    /**\n     * @notice Limits a uint256 value to the maximum uint112 value.\n     * @param  n The value to bound.\n     * @return The value limited to within uint112 bounds.\n     */\n    function bound112(uint256 n) internal pure returns (uint112) {\n        return uint112(min256(n, uint256(type(uint112).max)));\n    }\n\n    /**\n     * @notice Limits a uint256 value to the maximum uint128 value.\n     * @param  n The value to bound.\n     * @return The value limited to within uint128 bounds.\n     */\n    function bound128(uint256 n) internal pure returns (uint128) {\n        return uint128(min256(n, uint256(type(uint128).max)));\n    }\n\n    /**\n     * @notice Limits a uint256 value to the maximum uint240 value.\n     * @param  n The value to bound.\n     * @return The value limited to within uint240 bounds.\n     */\n    function bound240(uint256 n) internal pure returns (uint240) {\n        return uint240(min256(n, uint256(type(uint240).max)));\n    }\n\n    /**\n     * @notice Compares two uint32 values and returns the larger one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The larger value.\n     */\n    function max32(uint32 a, uint32 b) internal pure returns (uint32) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint40 values and returns the larger one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The larger value.\n     */\n    function max40(uint40 a, uint40 b) internal pure returns (uint40) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint128 values and returns the larger one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The larger value.\n     */\n    function max128(uint128 a, uint128 b) internal pure returns (uint128) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint240 values and returns the larger one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The larger value.\n     */\n    function max240(uint240 a, uint240 b) internal pure returns (uint240) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint32 values and returns the lesser one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The lesser value.\n     */\n    function min32(uint32 a, uint32 b) internal pure returns (uint32) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint40 values and returns the lesser one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The lesser value.\n     */\n    function min40(uint40 a, uint40 b) internal pure returns (uint40) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint240 values and returns the lesser one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The lesser value.\n     */\n    function min240(uint240 a, uint240 b) internal pure returns (uint240) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint112 values and returns the lesser one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The lesser value.\n     */\n    function min112(uint112 a, uint112 b) internal pure returns (uint112) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @notice Compares two uint256 values and returns the lesser one.\n     * @param  a Value to compare.\n     * @param  b Value to compare.\n     * @return The lesser value.\n     */\n    function min256(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev External interface of AccessControl declared to support ERC-165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev The `account` is missing a role.\n     */\n    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);\n\n    /**\n     * @dev The caller of a function is not the expected one.\n     *\n     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.\n     */\n    error AccessControlBadConfirmation();\n\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted to signal this.\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).\n     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n"},{"file_path":"lib/common/src/ERC20ExtendedUpgradeable.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { ERC3009Upgradeable } from \"./ERC3009Upgradeable.sol\";\n\nimport { IERC20 } from \"./interfaces/IERC20.sol\";\nimport { IERC20Extended } from \"./interfaces/IERC20Extended.sol\";\n\nabstract contract ERC20ExtendedUpgradeableStorageLayout {\n    /// @custom:storage-location erc7201:M0.storage.ERC20Extended\n    struct ERC20ExtendedStorageStruct {\n        mapping(address account => mapping(address spender => uint256 allowance)) allowance;\n        uint8 decimals;\n        string symbol;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.ERC20Extended\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _ERC20_EXTENDED_STORAGE_LOCATION =\n        0xcbbe23efb65c1eaba394256c463812c20abdb5376e247eba1d0e1e92054da100;\n\n    function _getERC20ExtendedStorageLocation() internal pure returns (ERC20ExtendedStorageStruct storage $) {\n        assembly {\n            $.slot := _ERC20_EXTENDED_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title  An upgradeable ERC20 token extended with EIP-2612 permits for signed approvals\n *         (via EIP-712 and with EIP-1271 and EIP-5267 compatibility).\n * @author M0 Labs\n */\nabstract contract ERC20ExtendedUpgradeable is\n    ERC20ExtendedUpgradeableStorageLayout,\n    ERC3009Upgradeable,\n    IERC20Extended\n{\n    /* ============ Variables ============ */\n\n    /**\n     * @inheritdoc IERC20Extended\n     * @dev Keeping this constant, despite `permit` parameter name differences, to ensure max EIP-2612 compatibility.\n     *      keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\")\n     */\n    bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;\n\n    /* ============ Initializer ============ */\n\n    function __ERC20ExtendedUpgradeable_init(\n        string memory name_,\n        string memory symbol_,\n        uint8 decimals_\n    ) internal onlyInitializing {\n        __ERC3009Upgradeable_init(name_);\n\n        ERC20ExtendedStorageStruct storage $ = _getERC20ExtendedStorageLocation();\n\n        $.decimals = decimals_;\n        $.symbol = symbol_;\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IERC20\n    function approve(address spender_, uint256 amount_) external returns (bool) {\n        _approve(msg.sender, spender_, amount_);\n        return true;\n    }\n\n    /// @inheritdoc IERC20Extended\n    function permit(\n        address owner_,\n        address spender_,\n        uint256 value_,\n        uint256 deadline_,\n        uint8 v_,\n        bytes32 r_,\n        bytes32 s_\n    ) external {\n        _revertIfInvalidSignature(owner_, _permitAndGetDigest(owner_, spender_, value_, deadline_), v_, r_, s_);\n    }\n\n    /// @inheritdoc IERC20Extended\n    function permit(\n        address owner_,\n        address spender_,\n        uint256 value_,\n        uint256 deadline_,\n        bytes memory signature_\n    ) external {\n        _revertIfInvalidSignature(owner_, _permitAndGetDigest(owner_, spender_, value_, deadline_), signature_);\n    }\n\n    /// @inheritdoc IERC20\n    function transfer(address recipient_, uint256 amount_) external returns (bool) {\n        _transfer(msg.sender, recipient_, amount_);\n        return true;\n    }\n\n    /// @inheritdoc IERC20\n    function transferFrom(address sender_, address recipient_, uint256 amount_) external returns (bool) {\n        ERC20ExtendedStorageStruct storage $ = _getERC20ExtendedStorageLocation();\n        uint256 spenderAllowance_ = $.allowance[sender_][msg.sender]; // Cache `spenderAllowance_` to stack.\n\n        if (spenderAllowance_ != type(uint256).max) {\n            if (spenderAllowance_ < amount_) revert InsufficientAllowance(msg.sender, spenderAllowance_, amount_);\n\n            unchecked {\n                _setAllowance($, sender_, msg.sender, spenderAllowance_ - amount_);\n            }\n        }\n\n        _transfer(sender_, recipient_, amount_);\n\n        return true;\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IERC20\n    function allowance(address account, address spender) public view returns (uint256) {\n        return _getERC20ExtendedStorageLocation().allowance[account][spender];\n    }\n\n    /// @inheritdoc IERC20\n    function decimals() external view virtual returns (uint8) {\n        return _getERC20ExtendedStorageLocation().decimals;\n    }\n\n    /// @inheritdoc IERC20\n    function name() external view virtual returns (string memory) {\n        return _getERC712ExtendedStorageLocation().name;\n    }\n\n    /// @inheritdoc IERC20\n    function symbol() external view virtual returns (string memory) {\n        return _getERC20ExtendedStorageLocation().symbol;\n    }\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @dev Approve `spender_` to spend `amount_` of tokens from `account_`.\n     * @param  account_ The address approving the allowance.\n     * @param  spender_ The address approved to spend the tokens.\n     * @param  amount_  The amount of tokens being approved for spending.\n     */\n    function _approve(address account_, address spender_, uint256 amount_) internal virtual {\n        _setAllowance(_getERC20ExtendedStorageLocation(), account_, spender_, amount_);\n        emit Approval(account_, spender_, amount_);\n    }\n\n    /**\n     * @dev Set the `amount_` of tokens `spender_` is allowed to spend from `account_`.\n     * @param $         ERC20Extended storage location.\n     * @param  account_ The address for which the allowance is set.\n     * @param  spender_ The address allowed to spend the tokens.\n     * @param  amount_  The amount of tokens being allowed for spending.\n     */\n    function _setAllowance(\n        ERC20ExtendedStorageStruct storage $,\n        address account_,\n        address spender_,\n        uint256 amount_\n    ) internal virtual {\n        $.allowance[account_][spender_] = amount_;\n    }\n\n    /**\n     * @dev    Performs the approval based on the permit info, validates the deadline, and returns the digest.\n     * @param  owner_    The address of the account approving the allowance.\n     * @param  spender_  The address of the account being allowed to spend the tokens.\n     * @param  amount_   The amount of tokens being approved for spending.\n     * @param  deadline_ The deadline by which the signature must be used.\n     * @return digest_   The EIP-712 digest of the permit.\n     */\n    function _permitAndGetDigest(\n        address owner_,\n        address spender_,\n        uint256 amount_,\n        uint256 deadline_\n    ) internal virtual returns (bytes32) {\n        _revertIfExpired(deadline_);\n\n        _approve(owner_, spender_, amount_);\n\n        unchecked {\n            // Nonce realistically cannot overflow.\n            return\n                _getDigest(\n                    keccak256(\n                        abi.encode(\n                            PERMIT_TYPEHASH,\n                            owner_,\n                            spender_,\n                            amount_,\n                            _getStatefulERC712ExtendedStorageLocation().nonces[owner_]++,\n                            deadline_\n                        )\n                    )\n                );\n        }\n    }\n}\n"},{"file_path":"src/MExtension.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\nimport { ERC20ExtendedUpgradeable } from \"../lib/common/src/ERC20ExtendedUpgradeable.sol\";\n\nimport { IERC20 } from \"../lib/common/src/interfaces/IERC20.sol\";\n\nimport { IMTokenLike } from \"./interfaces/IMTokenLike.sol\";\nimport { IMExtension } from \"./interfaces/IMExtension.sol\";\nimport { ISwapFacility } from \"./swap/interfaces/ISwapFacility.sol\";\n\n/**\n * @title  MExtension\n * @notice Upgradeable ERC20 Token contract for wrapping M into a non-rebasing token.\n * @author M0 Labs\n */\nabstract contract MExtension is IMExtension, ERC20ExtendedUpgradeable {\n    /* ============ Variables ============ */\n\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    /// @inheritdoc IMExtension\n    address public immutable mToken;\n\n    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable\n    /// @inheritdoc IMExtension\n    address public immutable swapFacility;\n\n    /* ============ Modifiers ============ */\n\n    /// @dev Modifier to check if caller is SwapFacility.\n    modifier onlySwapFacility() {\n        if (msg.sender != swapFacility) revert NotSwapFacility();\n        _;\n    }\n\n    /* ============ Constructor ============ */\n\n    /**\n     * @custom:oz-upgrades-unsafe-allow constructor\n     * @notice Constructs MExtension Implementation contract\n     * @dev    Sets immutable storage.\n     * @param  mToken_       The address of $M token.\n     * @param  swapFacility_ The address of Swap Facility.\n     */\n    constructor(address mToken_, address swapFacility_) {\n        _disableInitializers();\n\n        if ((mToken = mToken_) == address(0)) revert ZeroMToken();\n        if ((swapFacility = swapFacility_) == address(0)) revert ZeroSwapFacility();\n    }\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @notice Initializes the generic M extension token.\n     * @param name          The name of the token (e.g. \"HALO USD\").\n     * @param symbol        The symbol of the token (e.g. \"HUSD\").\n     */\n    function __MExtension_init(string memory name, string memory symbol) internal onlyInitializing {\n        __ERC20ExtendedUpgradeable_init(name, symbol, 6);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IMExtension\n    function wrap(address recipient, uint256 amount) external onlySwapFacility {\n        // NOTE: `msg.sender` is always SwapFacility contract.\n        //       `ISwapFacility.msgSender()` is used to ensure that the original caller is passed to `_beforeWrap`.\n        _wrap(ISwapFacility(msg.sender).msgSender(), recipient, amount);\n    }\n\n    /// @inheritdoc IMExtension\n    function unwrap(address /* recipient */, uint256 amount) external onlySwapFacility {\n        // NOTE: `msg.sender` is always SwapFacility contract.\n        //       `ISwapFacility.msgSender()` is used to ensure that the original caller is passed to `_beforeUnwrap`.\n        // NOTE: `recipient` is not used in this function as the $M is always sent to SwapFacility contract.\n        _unwrap(ISwapFacility(msg.sender).msgSender(), amount);\n    }\n\n    /// @inheritdoc IMExtension\n    function enableEarning() external virtual {\n        if (isEarningEnabled()) revert EarningIsEnabled();\n\n        emit EarningEnabled(currentIndex());\n\n        IMTokenLike(mToken).startEarning();\n    }\n\n    /// @inheritdoc IMExtension\n    function disableEarning() external virtual {\n        if (!isEarningEnabled()) revert EarningIsDisabled();\n\n        emit EarningDisabled(currentIndex());\n\n        IMTokenLike(mToken).stopEarning(address(this));\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IMExtension\n    function currentIndex() public view virtual returns (uint128) {\n        return IMTokenLike(mToken).currentIndex();\n    }\n\n    /// @inheritdoc IMExtension\n    function isEarningEnabled() public view virtual returns (bool) {\n        return IMTokenLike(mToken).isEarning(address(this));\n    }\n\n    /// @inheritdoc IERC20\n    function balanceOf(address account) public view virtual returns (uint256);\n\n    /* ============ Hooks For Internal Interactive Functions ============ */\n\n    /**\n     * @dev   Hook called before approval of M Extension token.\n     * @param account   The sender's address.\n     * @param spender   The spender address.\n     * @param amount    The amount to be approved.\n     */\n    function _beforeApprove(address account, address spender, uint256 amount) internal virtual {}\n\n    /**\n     * @dev    Hook called before wrapping M into M Extension token.\n     * @param  account   The account from which M is deposited.\n     * @param  recipient The account receiving the minted M Extension token.\n     * @param  amount    The amount of M deposited.\n     */\n    function _beforeWrap(address account, address recipient, uint256 amount) internal virtual {}\n\n    /**\n     * @dev   Hook called before unwrapping M Extension token.\n     * @param account   The account from which M Extension token is burned.\n     * @param amount    The amount of M Extension token burned.\n     */\n    function _beforeUnwrap(address account, uint256 amount) internal virtual {}\n\n    /**\n     * @dev   Hook called before transferring M Extension token.\n     * @param sender    The sender's address.\n     * @param recipient The recipient's address.\n     * @param amount    The amount to be transferred.\n     */\n    function _beforeTransfer(address sender, address recipient, uint256 amount) internal virtual {}\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @dev Approve `spender` to spend `amount` of tokens from `account`.\n     * @param account The address approving the allowance.\n     * @param spender The address approved to spend the tokens.\n     * @param amount  The amount of tokens being approved for spending.\n     */\n    function _approve(address account, address spender, uint256 amount) internal override {\n        // NOTE: Add extension-specific checks before approval.\n        _beforeApprove(account, spender, amount);\n\n        super._approve(account, spender, amount);\n    }\n\n    /**\n     * @dev    Wraps `amount` M from `account` into M Extension for `recipient`.\n     * @param  account   The original caller of SwapFacility functions.\n     * @param  recipient The account receiving the minted M Extension token.\n     * @param  amount    The amount of M deposited.\n     */\n    function _wrap(address account, address recipient, uint256 amount) internal {\n        _revertIfInvalidRecipient(recipient);\n        _revertIfInsufficientAmount(amount);\n\n        // NOTE: Add extension-specific checks before wrapping.\n        _beforeWrap(account, recipient, amount);\n\n        // NOTE: `msg.sender` is always SwapFacility contract.\n        // NOTE: The behavior of `IMTokenLike.transferFrom` is known, so its return can be ignored.\n        IMTokenLike(mToken).transferFrom(msg.sender, address(this), amount);\n\n        // NOTE: This method is overridden by the inheriting M Extension contract.\n        // NOTE: Mints precise amount of $M Extension token to `recipient`.\n        //       Option 1: $M transfer from an $M earner to another $M earner ($M Extension in earning state): rounds up → rounds up,\n        //                 0, 1, or XX extra wei may be locked in M Extension compared to the minted amount of $M Extension token.\n        //       Option 2: $M transfer from an $M non-earner to an $M earner ($M Extension in earning state): precise $M transfer → rounds down,\n        //                 0, -1, or -XX wei may be locked in $M Extension compared to the minted amount of $M Extension token.\n        //\n        _mint(recipient, amount);\n    }\n\n    /**\n     * @dev    Unwraps `amount` M Extension token from `account` into $M and transfers to SwapFacility.\n     * @param  account   The original caller of SwapFacility functions.\n     * @param  amount    The amount of M Extension token burned.\n     */\n    function _unwrap(address account, uint256 amount) internal {\n        _revertIfInsufficientAmount(amount);\n\n        // NOTE: Add extension-specific checks before unwrapping.\n        _beforeUnwrap(account, amount);\n\n        _revertIfInsufficientBalance(msg.sender, amount);\n\n        // NOTE: This method will be overridden by the inheriting M Extension contract.\n        // NOTE: Computes the actual decrease in the $M balance of the $M Extension contract.\n        //       Option 1: $M transfer from an $M earner ($M Extension in earning state) to another $M earner: round up → rounds up.\n        //       Option 2: $M transfer from an $M earner ($M Extension in earning state) to an $M non-earner: round up → precise $M transfer.\n        //       In both cases, 0, 1, or XX extra wei may be deducted from the $M Extension contract's $M balance compared to the burned amount of $M Extension token.\n        // NOTE: Always burn from SwapFacility as it is the only contract that can call this function.\n        _burn(msg.sender, amount);\n\n        // NOTE: The behavior of `IMTokenLike.transfer` is known, so its return can be ignored.\n        // NOTE: `msg.sender` is always SwapFacility contract.\n        IMTokenLike(mToken).transfer(msg.sender, amount);\n    }\n\n    /**\n     * @dev   Mints `amount` tokens to `recipient`.\n     * @param recipient The address to which the tokens will be minted.\n     * @param amount    The amount of tokens to mint.\n     */\n    function _mint(address recipient, uint256 amount) internal virtual;\n\n    /**\n     * @dev   Burns `amount` tokens from `account`.\n     * @param account The address from which the tokens will be burned.\n     * @param amount  The amount of tokens to burn.\n     */\n    function _burn(address account, uint256 amount) internal virtual;\n\n    /**\n     * @dev   Internal balance update function that needs to be implemented by the inheriting contract.\n     * @param sender    The sender's address.\n     * @param recipient The recipient's address.\n     * @param amount    The amount to be transferred.\n     */\n    function _update(address sender, address recipient, uint256 amount) internal virtual;\n\n    /**\n     * @dev   Internal ERC20 transfer function.\n     * @param sender    The sender's address.\n     * @param recipient The recipient's address.\n     * @param amount    The amount to be transferred.\n     */\n    function _transfer(address sender, address recipient, uint256 amount) internal override {\n        _revertIfInvalidRecipient(recipient);\n\n        // NOTE: Add extension-specific checks before transfers.\n        _beforeTransfer(sender, recipient, amount);\n\n        emit Transfer(sender, recipient, amount);\n\n        if (amount == 0) return;\n\n        _revertIfInsufficientBalance(sender, amount);\n\n        // NOTE: This method will be overridden by the inheriting M Extension contract.\n        _update(sender, recipient, amount);\n    }\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @dev    Returns the M Token balance of `account`.\n     * @param  account The account being queried.\n     * @return balance The M Token balance of the account.\n     */\n    function _mBalanceOf(address account) internal view returns (uint256) {\n        return IMTokenLike(mToken).balanceOf(account);\n    }\n\n    /**\n     * @dev   Reverts if `recipient` is address(0).\n     * @param recipient Address of a recipient.\n     */\n    function _revertIfInvalidRecipient(address recipient) internal pure {\n        if (recipient == address(0)) revert InvalidRecipient(recipient);\n    }\n\n    /**\n     * @dev   Reverts if `amount` is equal to 0.\n     * @param amount Amount of token.\n     */\n    function _revertIfInsufficientAmount(uint256 amount) internal pure {\n        if (amount == 0) revert InsufficientAmount(amount);\n    }\n\n    /**\n     * @dev   Reverts if `account` balance is below `amount`.\n     * @param account Address of an account.\n     * @param amount  Amount to transfer or burn.\n     */\n    function _revertIfInsufficientBalance(address account, uint256 amount) internal view {\n        uint256 balance = balanceOf(account);\n\n        if (balance < amount) revert InsufficientBalance(account, balance, amount);\n    }\n}\n"},{"file_path":"lib/common/src/ERC712ExtendedUpgradeable.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { Initializable } from \"../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\";\n\nimport { IERC712 } from \"./interfaces/IERC712.sol\";\nimport { IERC712Extended } from \"./interfaces/IERC712Extended.sol\";\n\nimport { SignatureChecker } from \"./libs/SignatureChecker.sol\";\n\nabstract contract ERC712ExtendedUpgradeableStorageLayout {\n    /// @custom:storage-location erc7201:M0.storage.ERC712Extended\n    struct ERC712ExtendedStorageStruct {\n        uint256 initialChainId;\n        bytes32 initialDomainSeparator;\n        string name;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.ERC712Extended\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _ERC712_EXTENDED_STORAGE_LOCATION =\n        0x103ce0bed7138196cdb0d79ef04042681b16e7a2c58d74b78443c813042ea100;\n\n    function _getERC712ExtendedStorageLocation() internal pure returns (ERC712ExtendedStorageStruct storage $) {\n        assembly {\n            $.slot := _ERC712_EXTENDED_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title  Typed structured data hashing and signing via EIP-712, extended by EIP-5267.\n * @author M0 Labs\n * @dev    An abstract implementation to satisfy EIP-712: https://eips.ethereum.org/EIPS/eip-712\n */\nabstract contract ERC712ExtendedUpgradeable is ERC712ExtendedUpgradeableStorageLayout, IERC712Extended, Initializable {\n    /* ============ Variables ============ */\n\n    /// @dev keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\")\n    bytes32 internal constant _EIP712_DOMAIN_HASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;\n\n    /// @dev keccak256(\"1\")\n    bytes32 internal constant _EIP712_VERSION_HASH = 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @notice Initializes the ERC712ExtendedUpgradeable contract.\n     * @param  name_ The name of the contract.\n     */\n    function __ERC712ExtendedUpgradeable_init(string memory name_) internal onlyInitializing {\n        ERC712ExtendedStorageStruct storage $ = _getERC712ExtendedStorageLocation();\n\n        $.name = name_;\n        $.initialChainId = block.chainid;\n        $.initialDomainSeparator = _getDomainSeparator();\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IERC712Extended\n    function eip712Domain()\n        external\n        view\n        virtual\n        returns (\n            bytes1 fields_,\n            string memory name_,\n            string memory version_,\n            uint256 chainId_,\n            address verifyingContract_,\n            bytes32 salt_,\n            uint256[] memory extensions_\n        )\n    {\n        return (\n            hex\"0f\", // 01111\n            _getERC712ExtendedStorageLocation().name,\n            \"1\",\n            block.chainid,\n            address(this),\n            bytes32(0),\n            new uint256[](0)\n        );\n    }\n\n    /// @inheritdoc IERC712\n    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n        ERC712ExtendedStorageStruct storage $ = _getERC712ExtendedStorageLocation();\n        return block.chainid == $.initialChainId ? $.initialDomainSeparator : _getDomainSeparator();\n    }\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @dev    Computes the EIP-712 domain separator.\n     * @return The EIP-712 domain separator.\n     */\n    function _getDomainSeparator() internal view returns (bytes32) {\n        return\n            keccak256(\n                abi.encode(\n                    _EIP712_DOMAIN_HASH,\n                    keccak256(bytes(_getERC712ExtendedStorageLocation().name)),\n                    _EIP712_VERSION_HASH,\n                    block.chainid,\n                    address(this)\n                )\n            );\n    }\n\n    /**\n     * @dev    Returns the digest to be signed, via EIP-712, given an internal digest (i.e. hash struct).\n     * @param  internalDigest_ The internal digest.\n     * @return The digest to be signed.\n     */\n    function _getDigest(bytes32 internalDigest_) internal view returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", DOMAIN_SEPARATOR(), internalDigest_));\n    }\n\n    /**\n     * @dev   Revert if the signature is expired.\n     * @param expiry_ Timestamp at which the signature expires or max uint256 for no expiry.\n     */\n    function _revertIfExpired(uint256 expiry_) internal view {\n        if (block.timestamp > expiry_) revert SignatureExpired(expiry_, block.timestamp);\n    }\n\n    /**\n     * @dev   Revert if the signature is invalid.\n     * @dev   We first validate if the signature is a valid ECDSA signature and return early if it is the case.\n     *        Then, we validate if it is a valid ERC-1271 signature, and return early if it is the case.\n     *        If not, we revert with the error from the ECDSA signature validation.\n     * @param signer_    The signer of the signature.\n     * @param digest_    The digest that was signed.\n     * @param signature_ The signature.\n     */\n    function _revertIfInvalidSignature(address signer_, bytes32 digest_, bytes memory signature_) internal view {\n        SignatureChecker.Error error_ = SignatureChecker.validateECDSASignature(signer_, digest_, signature_);\n\n        if (error_ == SignatureChecker.Error.NoError) return;\n\n        if (SignatureChecker.isValidERC1271Signature(signer_, digest_, signature_)) return;\n\n        _revertIfError(error_);\n    }\n\n    /**\n     * @dev    Returns the signer of a signed digest, via EIP-712, and reverts if the signature is invalid.\n     * @param  digest_ The digest that was signed.\n     * @param  v_      v of the signature.\n     * @param  r_      r of the signature.\n     * @param  s_      s of the signature.\n     * @return signer_ The signer of the digest.\n     */\n    function _getSignerAndRevertIfInvalidSignature(\n        bytes32 digest_,\n        uint8 v_,\n        bytes32 r_,\n        bytes32 s_\n    ) internal pure returns (address signer_) {\n        SignatureChecker.Error error_;\n\n        (error_, signer_) = SignatureChecker.recoverECDSASigner(digest_, v_, r_, s_);\n\n        _revertIfError(error_);\n    }\n\n    /**\n     * @dev   Revert if the signature is invalid.\n     * @param signer_ The signer of the signature.\n     * @param digest_ The digest that was signed.\n     * @param r_      An ECDSA/secp256k1 signature parameter.\n     * @param vs_     An ECDSA/secp256k1 short signature parameter.\n     */\n    function _revertIfInvalidSignature(address signer_, bytes32 digest_, bytes32 r_, bytes32 vs_) internal pure {\n        _revertIfError(SignatureChecker.validateECDSASignature(signer_, digest_, r_, vs_));\n    }\n\n    /**\n     * @dev   Revert if the signature is invalid.\n     * @param signer_ The signer of the signature.\n     * @param digest_ The digest that was signed.\n     * @param v_      v of the signature.\n     * @param r_      r of the signature.\n     * @param s_      s of the signature.\n     */\n    function _revertIfInvalidSignature(\n        address signer_,\n        bytes32 digest_,\n        uint8 v_,\n        bytes32 r_,\n        bytes32 s_\n    ) internal pure {\n        _revertIfError(SignatureChecker.validateECDSASignature(signer_, digest_, v_, r_, s_));\n    }\n\n    /**\n     * @dev   Revert if error.\n     * @param error_ The SignatureChecker Error enum.\n     */\n    function _revertIfError(SignatureChecker.Error error_) private pure {\n        if (error_ == SignatureChecker.Error.NoError) return;\n        if (error_ == SignatureChecker.Error.InvalidSignature) revert InvalidSignature();\n        if (error_ == SignatureChecker.Error.InvalidSignatureLength) revert InvalidSignatureLength();\n        if (error_ == SignatureChecker.Error.InvalidSignatureS) revert InvalidSignatureS();\n        if (error_ == SignatureChecker.Error.InvalidSignatureV) revert InvalidSignatureV();\n        if (error_ == SignatureChecker.Error.SignerMismatch) revert SignerMismatch();\n\n        revert InvalidSignature();\n    }\n}\n"},{"file_path":"lib/common/src/interfaces/IERC3009.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { IStatefulERC712 } from \"./IStatefulERC712.sol\";\n\n/**\n * @title  Transfer via signed authorization following EIP-3009 standard.\n * @author M^0 Labs\n * @dev    The interface as defined by EIP-3009: https://eips.ethereum.org/EIPS/eip-3009\n */\ninterface IERC3009 is IStatefulERC712 {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when an authorization has been canceled.\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the canceled authorization.\n     */\n    event AuthorizationCanceled(address indexed authorizer, bytes32 indexed nonce);\n\n    /**\n     * @notice Emitted when an authorization has been used.\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the used authorization.\n     */\n    event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce);\n\n    /* ============ Custom Errors ============ */\n\n    /**\n     * @notice Emitted when an authorization has already been used.\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the used authorization.\n     */\n    error AuthorizationAlreadyUsed(address authorizer, bytes32 nonce);\n\n    /**\n     * @notice Emitted when an authorization is expired.\n     * @param  timestamp   Timestamp at which the transaction was submitted.\n     * @param  validBefore Timestamp before which the authorization would have been valid.\n     */\n    error AuthorizationExpired(uint256 timestamp, uint256 validBefore);\n\n    /**\n     * @notice Emitted when an authorization is not yet valid.\n     * @param  timestamp  Timestamp at which the transaction was submitted.\n     * @param  validAfter Timestamp after which the authorization will be valid.\n     */\n    error AuthorizationNotYetValid(uint256 timestamp, uint256 validAfter);\n\n    /**\n     * @notice Emitted when the caller of `receiveWithAuthorization` is not the payee.\n     * @param  caller Caller's address.\n     * @param  payee  Payee's address.\n     */\n    error CallerMustBePayee(address caller, address payee);\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Execute a transfer with a signed authorization.\n     * @param  from        Payer's address (Authorizer).\n     * @param  to          Payee's address.\n     * @param  value       Amount to be transferred.\n     * @param  validAfter  The time after which this is valid (unix time).\n     * @param  validBefore The time before which this is valid (unix time).\n     * @param  nonce       Unique nonce.\n     * @param  signature   A byte array ECDSA/secp256k1 signature (encoded r, s, v).\n     */\n    function transferWithAuthorization(\n        address from,\n        address to,\n        uint256 value,\n        uint256 validAfter,\n        uint256 validBefore,\n        bytes32 nonce,\n        bytes memory signature\n    ) external;\n\n    /**\n     * @notice Execute a transfer with a signed authorization.\n     * @param  from        Payer's address (Authorizer).\n     * @param  to          Payee's address.\n     * @param  value       Amount to be transferred.\n     * @param  validAfter  The time after which this is valid (unix time).\n     * @param  validBefore The time before which this is valid (unix time).\n     * @param  nonce       Unique nonce.\n     * @param  r           An ECDSA/secp256k1 signature parameter.\n     * @param  vs          An ECDSA/secp256k1 short signature parameter.\n     */\n    function transferWithAuthorization(\n        address from,\n        address to,\n        uint256 value,\n        uint256 validAfter,\n        uint256 validBefore,\n        bytes32 nonce,\n        bytes32 r,\n        bytes32 vs\n    ) external;\n\n    /**\n     * @notice Execute a transfer with a signed authorization.\n     * @param  from        Payer's address (Authorizer).\n     * @param  to          Payee's address.\n     * @param  value       Amount to be transferred.\n     * @param  validAfter  The time after which this is valid (unix time).\n     * @param  validBefore The time before which this is valid (unix time).\n     * @param  nonce       Unique nonce.\n     * @param  v           v of the signature.\n     * @param  r           r of the signature.\n     * @param  s           s of the signature.\n     */\n    function transferWithAuthorization(\n        address from,\n        address to,\n        uint256 value,\n        uint256 validAfter,\n        uint256 validBefore,\n        bytes32 nonce,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @notice Receive a transfer with a signed authorization from the payer.\n     * @dev    This has an additional check to ensure that the payee's address matches\n     *         the caller of this function to prevent front-running attacks.\n     *         (See security considerations)\n     * @param  from        Payer's address (Authorizer).\n     * @param  to          Payee's address.\n     * @param  value       Amount to be transferred.\n     * @param  validAfter  The time after which this is valid (unix time).\n     * @param  validBefore The time before which this is valid (unix time).\n     * @param  nonce       Unique nonce.\n     * @param  signature   A byte array ECDSA/secp256k1 signature (encoded r, s, v).\n     */\n    function receiveWithAuthorization(\n        address from,\n        address to,\n        uint256 value,\n        uint256 validAfter,\n        uint256 validBefore,\n        bytes32 nonce,\n        bytes memory signature\n    ) external;\n\n    /**\n     * @notice Receive a transfer with a signed authorization from the payer.\n     * @dev    This has an additional check to ensure that the payee's address matches\n     *         the caller of this function to prevent front-running attacks.\n     *         (See security considerations)\n     * @param  from        Payer's address (Authorizer).\n     * @param  to          Payee's address.\n     * @param  value       Amount to be transferred.\n     * @param  validAfter  The time after which this is valid (unix time).\n     * @param  validBefore The time before which this is valid (unix time).\n     * @param  nonce       Unique nonce.\n     * @param  r           An ECDSA/secp256k1 signature parameter.\n     * @param  vs          An ECDSA/secp256k1 short signature parameter.\n     */\n    function receiveWithAuthorization(\n        address from,\n        address to,\n        uint256 value,\n        uint256 validAfter,\n        uint256 validBefore,\n        bytes32 nonce,\n        bytes32 r,\n        bytes32 vs\n    ) external;\n\n    /**\n     * @notice Receive a transfer with a signed authorization from the payer.\n     * @dev    This has an additional check to ensure that the payee's address matches\n     *         the caller of this function to prevent front-running attacks.\n     *         (See security considerations)\n     * @param  from        Payer's address (Authorizer).\n     * @param  to          Payee's address.\n     * @param  value       Amount to be transferred.\n     * @param  validAfter  The time after which this is valid (unix time).\n     * @param  validBefore The time before which this is valid (unix time).\n     * @param  nonce       Unique nonce.\n     * @param  v           v of the signature.\n     * @param  r           r of the signature.\n     * @param  s           s of the signature.\n     */\n    function receiveWithAuthorization(\n        address from,\n        address to,\n        uint256 value,\n        uint256 validAfter,\n        uint256 validBefore,\n        bytes32 nonce,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @notice Attempt to cancel an authorization.\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the authorization.\n     * @param  signature  A byte array ECDSA/secp256k1 signature (encoded r, s, v).\n     */\n    function cancelAuthorization(address authorizer, bytes32 nonce, bytes memory signature) external;\n\n    /**\n     * @notice Attempt to cancel an authorization.\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the authorization.\n     * @param  r          An ECDSA/secp256k1 signature parameter.\n     * @param  vs         An ECDSA/secp256k1 short signature parameter.\n     */\n    function cancelAuthorization(address authorizer, bytes32 nonce, bytes32 r, bytes32 vs) external;\n\n    /**\n     * @notice Attempt to cancel an authorization.\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the authorization.\n     * @param  v          v of the signature.\n     * @param  r          r of the signature.\n     * @param  s          s of the signature.\n     */\n    function cancelAuthorization(address authorizer, bytes32 nonce, uint8 v, bytes32 r, bytes32 s) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /**\n     * @notice Returns the state of an authorization.\n     * @dev    Nonces are randomly generated 32-byte data unique to the authorizer's address\n     * @param  authorizer Authorizer's address.\n     * @param  nonce      Nonce of the authorization.\n     * @return True if the nonce is used.\n     */\n    function authorizationState(address authorizer, bytes32 nonce) external view returns (bool);\n\n    /// @notice Returns `transferWithAuthorization` typehash.\n    function TRANSFER_WITH_AUTHORIZATION_TYPEHASH() external view returns (bytes32);\n\n    /// @notice Returns `receiveWithAuthorization` typehash.\n    function RECEIVE_WITH_AUTHORIZATION_TYPEHASH() external view returns (bytes32);\n\n    /// @notice Returns `cancelAuthorization` typehash.\n    function CANCEL_AUTHORIZATION_TYPEHASH() external view returns (bytes32);\n}\n"},{"file_path":"lib/common/src/interfaces/IERC1271.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\n/**\n * @title  Standard Signature Validation Method for Contracts via EIP-1271.\n * @author M^0 Labs\n * @dev    The interface as defined by EIP-1271: https://eips.ethereum.org/EIPS/eip-1271\n */\ninterface IERC1271 {\n    /**\n     * @dev    Returns a specific magic value if the provided signature is valid for the provided digest.\n     * @param  digest     Hash of the data purported to have been signed.\n     * @param  signature  Signature byte array associated with the digest.\n     * @return magicValue Magic value 0x1626ba7e if the signature is valid.\n     */\n    function isValidSignature(bytes32 digest, bytes memory signature) external view returns (bytes4 magicValue);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"src/projects/jmi/IJMIExtension.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\nimport { IMYieldToOne } from \"../yieldToOne/interfaces/IMYieldToOne.sol\";\n\ninterface IJMIExtension is IMYieldToOne {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when asset cap is set.\n     * @param  asset Address of the asset.\n     * @param  cap   Maximum allowed amount of `asset` that can back the extension.\n     */\n    event AssetCapSet(address indexed asset, uint256 cap);\n\n    /**\n     * @notice Emitted when an asset is replaced with M.\n     * @param  asset       Address of the asset.\n     * @param  assetAmount Amount of asset replaced with M.\n     * @param  recipient   Address that received the M.\n     * @param  mAmount     Amount of M sent to the recipient.\n     */\n    event AssetReplacedWithM(address indexed asset, uint256 assetAmount, address indexed recipient, uint256 mAmount);\n\n    /* ============ Custom Errors ============ */\n\n    /**\n     * @notice Emitted if the asset cap is reached.\n     * @param  asset Address of the asset.\n     */\n    error AssetCapReached(address asset);\n\n    /**\n     * @notice Emitted if `replaceAssetWithM` is called but there is not enough asset to replace M with.\n     * @param  asset          Address of the asset.\n     * @param  amount         Amount of M to unwrap requested.\n     * @param  assetAvailable Amount of M available.\n     */\n    error InsufficientAssetBacking(address asset, uint256 amount, uint256 assetAvailable);\n\n    /**\n     * @notice Emitted when wrapping `asset` for extension token and receiving less than expected.\n     * @param  asset          Address of the asset.\n     * @param  amountExpected Amount of `asset` expected.\n     * @param  amountReceived Amount of `asset` received.\n     */\n    error InsufficientAssetReceived(address asset, uint256 amountExpected, uint256 amountReceived);\n\n    /**\n     * @notice Emitted if `unwrap()` is called but there is not enough M to unwrap with.\n     * @param  amount     Amount of M to unwrap requested.\n     * @param  mAvailable Amount of M available.\n     */\n    error InsufficientMBacking(uint256 amount, uint256 mAvailable);\n\n    /**\n     * @notice Emitted if an invalid asset is used.\n     * @param  asset Address of the invalid asset.\n     */\n    error InvalidAsset(address asset);\n\n    /// @notice Emitted in initializer if Asset Cap Manager is 0x0.\n    error ZeroAssetCapManager();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Mint extension tokens by depositing `asset` tokens.\n     * @dev    MUST only be callable by the SwapFacility.\n     * @dev    `amount` must be formatted in the `asset` token's decimals.\n     * @param  asset     Address of the asset to deposit.\n     * @param  recipient Address that will receive the extension tokens.\n     * @param  amount    Amount of asset tokens to deposit.\n     */\n    function wrap(address asset, address recipient, uint256 amount) external;\n\n    /**\n     * @notice Allows a M holder to swap M for the `asset` token.\n     * @dev    MUST only be callable by the SwapFacility.\n     * @dev    `amount` MUST be formatted in the M token's decimals.\n     * @param  asset     Address of the asset to receive.\n     * @param  recipient Address that will receive the `asset` token.\n     * @param  amount    Amount of M to swap for `asset` token.\n     */\n    function replaceAssetWithM(address asset, address recipient, uint256 amount) external;\n\n    /**\n     * @notice Sets the asset cap for a given `asset`.\n     * @dev    MUST only be callable by an account with the ASSET_CAP_MANAGER_ROLE.\n     * @param  asset Address of the asset.\n     * @param  cap   Maximum allowed amount of `asset` that can back the extension.\n     */\n    function setAssetCap(address asset, uint256 cap) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The role that can set the assets cap.\n    function ASSET_CAP_MANAGER_ROLE() external view returns (bytes32);\n\n    /// @notice Number of decimals used by the M token.\n    function M_DECIMALS() external view returns (uint8);\n\n    /// @notice Gets the cached balance of a given asset held by the extension.\n    function assetBalanceOf(address asset) external view returns (uint256);\n\n    /// @notice Gets the asset cap for a given asset.\n    function assetCap(address asset) external view returns (uint256);\n\n    /// @notice Gets the cached decimals of a given asset.\n    function assetDecimals(address asset) external view returns (uint8);\n\n    /// @notice Gets the total non-M assets held by the extension.\n    function totalAssets() external view returns (uint256);\n\n    /// @notice Checks if an asset is allowed as backing.\n    function isAllowedAsset(address asset) external view returns (bool);\n\n    /**\n     * @notice Checks if wrapping a `amount` of `asset` is allowed.\n     * @dev    `amount` MUST be formatted in `asset`'s decimals.\n     * @param  asset  Address of the asset.\n     * @param  amount Amount of `asset` to wrap.\n     * @return True if allowed, false otherwise.\n     */\n    function isAllowedToWrap(address asset, uint256 amount) external view returns (bool);\n\n    /**\n     * @notice Checks if unwrapping `amount` of extension tokens is allowed.\n     * @dev    `amount` MUST be formatted in extension's decimals (i.e. 6).\n     * @param  amount Amount of extension tokens to unwrap, formatted in extension's decimals.\n     * @return True if allowed, false otherwise.\n     */\n    function isAllowedToUnwrap(uint256 amount) external view returns (bool);\n\n    /**\n     * @notice Checks if replacing `asset` with M is allowed.\n     * @dev    `amount` MUST be formatted in `asset`'s decimals.\n     * @param  asset  Address of the asset.\n     * @param  amount Amount of `asset` to replace, formatted in `asset`'s decimals.\n     * @return True if allowed, false otherwise.\n     */\n    function isAllowedToReplaceAssetWithM(address asset, uint256 amount) external view returns (bool);\n}\n"},{"file_path":"src/interfaces/IMExtension.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\nimport { IERC20Extended } from \"../../lib/common/src/interfaces/IERC20Extended.sol\";\n\n/**\n * @title  M Extension interface extending Extended ERC20,\n *         includes additional enable/disable earnings and index logic.\n * @author M0 Labs\n */\ninterface IMExtension is IERC20Extended {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when M extension earning is enabled.\n     * @param  index The index at the moment earning is enabled.\n     */\n    event EarningEnabled(uint128 index);\n\n    /**\n     * @notice Emitted when M extension earning is disabled.\n     * @param  index The index at the moment earning is disabled.\n     */\n    event EarningDisabled(uint128 index);\n\n    /* ============ Custom Errors ============ */\n\n    /// @notice Emitted when performing an operation that is not allowed when earning is disabled.\n    error EarningIsDisabled();\n\n    /// @notice Emitted when performing an operation that is not allowed when earning is enabled.\n    error EarningIsEnabled();\n\n    /**\n     * @notice Emitted when there is insufficient balance to decrement from `account`.\n     * @param  account The account with insufficient balance.\n     * @param  balance The balance of the account.\n     * @param  amount  The amount to decrement.\n     */\n    error InsufficientBalance(address account, uint256 balance, uint256 amount);\n\n    /// @notice Emitted in constructor if M Token is 0x0.\n    error ZeroMToken();\n\n    /// @notice Emitted in constructor if Swap Facility is 0x0.\n    error ZeroSwapFacility();\n\n    /// @notice Emitted in `wrap` and `unwrap` functions if the caller is not the Swap Facility.\n    error NotSwapFacility();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Enables earning of extension token if allowed by the TTG Registrar and if it has never been done.\n     * @dev SHOULD be virtual to allow extensions to override it.\n     */\n    function enableEarning() external;\n\n    /**\n     * @notice Disables earning of extension token if disallowed by the TTG Registrar and if it has never been done.\n     * @dev SHOULD be virtual to allow extensions to override it.\n     */\n    function disableEarning() external;\n\n    /**\n     * @notice Wraps `amount` M from the caller into extension token for `recipient`.\n     * @dev    Can only be called by the SwapFacility.\n     * @param  recipient The account receiving the minted M extension token.\n     * @param  amount    The amount of M extension token minted.\n     */\n    function wrap(address recipient, uint256 amount) external;\n\n    /**\n     * @notice Unwraps `amount` extension token from the caller into M for `recipient`.\n     * @dev    Can only be called by the SwapFacility.\n     * @param  recipient The account receiving the withdrawn M,\n     *         it will always be the SwapFacility (keep `recipient` for backward compatibility).\n     * @param  amount    The amount of M extension token burned.\n     */\n    function unwrap(address recipient, uint256 amount) external;\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The address of the M Token contract.\n    function mToken() external view returns (address);\n\n    /// @notice The address of the SwapFacility contract.\n    function swapFacility() external view returns (address);\n\n    /**\n     * @notice Whether M extension earning is enabled.\n     * @dev SHOULD be virtual to allow extensions to override it.\n     */\n    function isEarningEnabled() external view returns (bool);\n\n    /**\n     * @notice Returns the current index for M extension earnings.\n     * @dev SHOULD be virtual to allow extensions to override it.\n     */\n    function currentIndex() external view returns (uint128);\n}\n"},{"file_path":"src/projects/yieldToOne/MYieldToOne.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity 0.8.26;\n\nimport { IERC20 } from \"../../../lib/common/src/interfaces/IERC20.sol\";\n\nimport { IMYieldToOne } from \"./interfaces/IMYieldToOne.sol\";\n\nimport { Freezable } from \"../../components/freezable/Freezable.sol\";\nimport { Pausable } from \"../../components/pausable/Pausable.sol\";\nimport { MExtension } from \"../../MExtension.sol\";\n\nabstract contract MYieldToOneStorageLayout {\n    /// @custom:storage-location erc7201:M0.storage.MYieldToOne\n    struct MYieldToOneStorageStruct {\n        uint256 totalSupply;\n        address yieldRecipient;\n        mapping(address account => uint256 balance) balanceOf;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.MYieldToOne\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _M_YIELD_TO_ONE_STORAGE_LOCATION =\n        0xee2f6fc7e2e5879b17985791e0d12536cba689bda43c77b8911497248f4af100;\n\n    function _getMYieldToOneStorageLocation() internal pure returns (MYieldToOneStorageStruct storage $) {\n        assembly {\n            $.slot := _M_YIELD_TO_ONE_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title  MYieldToOne\n * @notice Upgradeable ERC20 Token contract for wrapping M into a non-rebasing token\n *         with yield claimable by a single recipient.\n * @author M0 Labs\n */\ncontract MYieldToOne is IMYieldToOne, MYieldToOneStorageLayout, MExtension, Freezable, Pausable {\n    /* ============ Variables ============ */\n\n    /// @inheritdoc IMYieldToOne\n    bytes32 public constant YIELD_RECIPIENT_MANAGER_ROLE = keccak256(\"YIELD_RECIPIENT_MANAGER_ROLE\");\n\n    /* ============ Constructor ============ */\n\n    /**\n     * @custom:oz-upgrades-unsafe-allow constructor\n     * @notice Constructs MYieldToOne Implementation contract\n     * @dev    Sets immutable storage.\n     * @param  mToken       The address of $M token.\n     * @param  swapFacility The address of Swap Facility.\n     */\n    constructor(address mToken, address swapFacility) MExtension(mToken, swapFacility) {}\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @dev   Initializes the M extension token with yield claimable by a single recipient.\n     * @param name                  The name of the token (e.g. \"M Yield to One\").\n     * @param symbol                The symbol of the token (e.g. \"MYO\").\n     * @param yieldRecipient_       The address of a yield destination.\n     * @param admin                 The address of an admin.\n     * @param freezeManager         The address of a freeze manager.\n     * @param yieldRecipientManager The address of a yield recipient setter.\n     * @param pauser                The address of a pauser.\n     */\n    function initialize(\n        string memory name,\n        string memory symbol,\n        address yieldRecipient_,\n        address admin,\n        address freezeManager,\n        address yieldRecipientManager,\n        address pauser\n    ) public virtual initializer {\n        __MYieldToOne_init(name, symbol, yieldRecipient_, admin, freezeManager, yieldRecipientManager, pauser);\n    }\n\n    /**\n     * @notice Initializes the MYieldToOne token.\n     * @param name                  The name of the token (e.g. \"M Yield to One\").\n     * @param symbol                The symbol of the token (e.g. \"MYO\").\n     * @param yieldRecipient_       The address of a yield destination.\n     * @param admin                 The address of an admin.\n     * @param freezeManager         The address of a freeze manager.\n     * @param yieldRecipientManager The address of a yield recipient setter.\n     * @param pauser                The address of a pauser.\n     */\n    function __MYieldToOne_init(\n        string memory name,\n        string memory symbol,\n        address yieldRecipient_,\n        address admin,\n        address freezeManager,\n        address yieldRecipientManager,\n        address pauser\n    ) internal onlyInitializing {\n        if (yieldRecipientManager == address(0)) revert ZeroYieldRecipientManager();\n        if (admin == address(0)) revert ZeroAdmin();\n\n        __MExtension_init(name, symbol);\n        __Freezable_init(freezeManager);\n        __Pausable_init(pauser);\n\n        _setYieldRecipient(yieldRecipient_);\n\n        _grantRole(DEFAULT_ADMIN_ROLE, admin);\n        _grantRole(YIELD_RECIPIENT_MANAGER_ROLE, yieldRecipientManager);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IMYieldToOne\n    function claimYield() public virtual returns (uint256) {\n        _beforeClaimYield();\n\n        uint256 yield_ = yield();\n\n        if (yield_ == 0) return 0;\n\n        emit YieldClaimed(yield_);\n\n        _mint(yieldRecipient(), yield_);\n\n        return yield_;\n    }\n\n    /// @inheritdoc IMYieldToOne\n    function setYieldRecipient(address account) external virtual onlyRole(YIELD_RECIPIENT_MANAGER_ROLE) {\n        // Claim yield for the previous yield recipient.\n        claimYield();\n\n        _setYieldRecipient(account);\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IERC20\n    function balanceOf(address account) public view override returns (uint256) {\n        return _getMYieldToOneStorageLocation().balanceOf[account];\n    }\n\n    /// @inheritdoc IERC20\n    function totalSupply() public view returns (uint256) {\n        return _getMYieldToOneStorageLocation().totalSupply;\n    }\n\n    /// @inheritdoc IMYieldToOne\n    function yield() public view virtual returns (uint256) {\n        unchecked {\n            uint256 balance_ = _mBalanceOf(address(this));\n            uint256 totalSupply_ = totalSupply();\n\n            return balance_ > totalSupply_ ? balance_ - totalSupply_ : 0;\n        }\n    }\n\n    /// @inheritdoc IMYieldToOne\n    function yieldRecipient() public view returns (address) {\n        return _getMYieldToOneStorageLocation().yieldRecipient;\n    }\n\n    /* ============ Hooks For Internal Interactive Functions ============ */\n\n    /**\n     * @dev    Hooks called before approval of M extension spend.\n     * @param  account The account from which M is deposited.\n     * @param  spender The account spending M Extension token.\n     */\n    function _beforeApprove(address account, address spender, uint256 /* amount */) internal view virtual override {\n        FreezableStorageStruct storage $ = _getFreezableStorageLocation();\n\n        _revertIfFrozen($, account);\n        _revertIfFrozen($, spender);\n    }\n\n    /**\n     * @dev    Hooks called before wrapping M into M Extension token.\n     * @param  account   The account from which M is deposited.\n     * @param  recipient The account receiving the minted M Extension token.\n     */\n    function _beforeWrap(address account, address recipient, uint256 /* amount */) internal view virtual override {\n        _requireNotPaused();\n        FreezableStorageStruct storage $ = _getFreezableStorageLocation();\n\n        _revertIfFrozen($, account);\n        _revertIfFrozen($, recipient);\n    }\n\n    /**\n     * @dev   Hook called before unwrapping M Extension token.\n     * @param account The account from which M Extension token is burned.\n     */\n    function _beforeUnwrap(address account, uint256 /* amount */) internal view virtual override {\n        _requireNotPaused();\n        _revertIfFrozen(_getFreezableStorageLocation(), account);\n    }\n\n    /**\n     * @dev   Hook called before transferring M Extension token.\n     * @param sender    The address from which the tokens are being transferred.\n     * @param recipient The address to which the tokens are being transferred.\n     */\n    function _beforeTransfer(address sender, address recipient, uint256 /* amount */) internal view virtual override {\n        _requireNotPaused();\n        FreezableStorageStruct storage $ = _getFreezableStorageLocation();\n\n        _revertIfFrozen($, msg.sender);\n\n        _revertIfFrozen($, sender);\n        _revertIfFrozen($, recipient);\n    }\n\n    /**\n     * @dev   Hook called before claiming yield from the M Extension token. To be overridden in derived extensions.\n     */\n    function _beforeClaimYield() internal view virtual {}\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @dev   Mints `amount` tokens to `recipient`.\n     * @param recipient The address whose account balance will be incremented.\n     * @param amount    The present amount of tokens to mint.`\n     */\n    function _mint(address recipient, uint256 amount) internal override {\n        MYieldToOneStorageStruct storage $ = _getMYieldToOneStorageLocation();\n\n        // NOTE: Can be `unchecked` because the max amount of $M is never greater than `type(uint240).max`.\n        unchecked {\n            $.balanceOf[recipient] += amount;\n            $.totalSupply += amount;\n        }\n\n        emit Transfer(address(0), recipient, amount);\n    }\n\n    /**\n     * @dev   Burns `amount` tokens from `account`.\n     * @param account The address whose account balance will be decremented.\n     * @param amount  The present amount of tokens to burn.\n     */\n    function _burn(address account, uint256 amount) internal override {\n        MYieldToOneStorageStruct storage $ = _getMYieldToOneStorageLocation();\n\n        // NOTE: Can be `unchecked` because `_revertIfInsufficientBalance` is used in MExtension.\n        unchecked {\n            $.balanceOf[account] -= amount;\n            $.totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev   Internal balance update function called on transfer.\n     * @param sender    The sender's address.\n     * @param recipient The recipient's address.\n     * @param amount    The amount to be transferred.\n     */\n    function _update(address sender, address recipient, uint256 amount) internal override {\n        MYieldToOneStorageStruct storage $ = _getMYieldToOneStorageLocation();\n\n        // NOTE: Can be `unchecked` because `_revertIfInsufficientBalance` for `sender` is used in MExtension.\n        unchecked {\n            $.balanceOf[sender] -= amount;\n            $.balanceOf[recipient] += amount;\n        }\n    }\n\n    /**\n     * @dev Sets the yield recipient.\n     * @param yieldRecipient_ The address of the new yield recipient.\n     */\n    function _setYieldRecipient(address yieldRecipient_) internal {\n        if (yieldRecipient_ == address(0)) revert ZeroYieldRecipient();\n\n        MYieldToOneStorageStruct storage $ = _getMYieldToOneStorageLocation();\n\n        if (yieldRecipient_ == $.yieldRecipient) return;\n\n        $.yieldRecipient = yieldRecipient_;\n\n        emit YieldRecipientSet(yieldRecipient_);\n    }\n}\n"},{"file_path":"lib/common/src/ERC3009Upgradeable.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\nimport { Initializable } from \"../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol\";\nimport { IERC3009 } from \"./interfaces/IERC3009.sol\";\n\nimport { StatefulERC712Upgradeable } from \"./StatefulERC712Upgradeable.sol\";\n\nabstract contract ERC3009UpgradeableStorageLayout {\n    /// @custom:storage-location erc7201:M0.storage.ERC3009\n    struct ERC3009StorageStruct {\n        mapping(address authorizer => mapping(bytes32 nonce => bool isNonceUsed)) authorizationState;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.ERC3009\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _ERC3009_STORAGE_LOCATION =\n        0x1116a1d33aa5fb91b2652b3b0fdb63704173742d6dbecaf4256ebe33a4888600;\n\n    function _getERC3009StorageLocation() internal pure returns (ERC3009StorageStruct storage $) {\n        assembly {\n            $.slot := _ERC3009_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title  ERC3009 implementation allowing the transfer of fungible assets via a signed authorization.\n * @author M0 Labs\n * @dev    Inherits from ERC712ExtendedUpgradeable and StatefulERC712Upgradeable.\n */\nabstract contract ERC3009Upgradeable is IERC3009, ERC3009UpgradeableStorageLayout, StatefulERC712Upgradeable {\n    /* ============ Variables ============ */\n\n    // solhint-disable-next-line max-line-length\n    /// @dev        keccak256(\"TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)\")\n    /// @inheritdoc IERC3009\n    bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH =\n        0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267;\n\n    // solhint-disable-next-line max-line-length\n    /// @dev        keccak256(\"ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)\")\n    /// @inheritdoc IERC3009\n    bytes32 public constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH =\n        0xd099cc98ef71107a616c4f0f941f04c322d8e254fe26b3c6668db87aae413de8;\n\n    /**\n     * @inheritdoc IERC3009\n     * @dev        keccak256(\"CancelAuthorization(address authorizer,bytes32 nonce)\")\n     */\n    bytes32 public constant CANCEL_AUTHORIZATION_TYPEHASH =\n        0x158b0a9edf7a828aad02f63cd515c68ef2f50ba807396f6d12842833a1597429;\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @notice Initializes the ERC3009Upgradeable contract.\n     * @param  name_ The name of the contract.\n     */\n    function __ERC3009Upgradeable_init(string memory name_) internal onlyInitializing {\n        __StatefulERC712ExtendedUpgradeable_init(name_);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IERC3009\n    function transferWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_,\n        bytes memory signature_\n    ) external {\n        _revertIfInvalidSignature(\n            from_,\n            _getTransferWithAuthorizationDigest(from_, to_, value_, validAfter_, validBefore_, nonce_),\n            signature_\n        );\n\n        _transferWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function transferWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_,\n        bytes32 r_,\n        bytes32 vs_\n    ) external {\n        _revertIfInvalidSignature(\n            from_,\n            _getTransferWithAuthorizationDigest(from_, to_, value_, validAfter_, validBefore_, nonce_),\n            r_,\n            vs_\n        );\n\n        _transferWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function transferWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_,\n        uint8 v_,\n        bytes32 r_,\n        bytes32 s_\n    ) external {\n        _revertIfInvalidSignature(\n            from_,\n            _getTransferWithAuthorizationDigest(from_, to_, value_, validAfter_, validBefore_, nonce_),\n            v_,\n            r_,\n            s_\n        );\n\n        _transferWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function receiveWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_,\n        bytes memory signature_\n    ) external {\n        _revertIfInvalidSignature(\n            from_,\n            _getReceiveWithAuthorizationDigest(from_, to_, value_, validAfter_, validBefore_, nonce_),\n            signature_\n        );\n\n        _receiveWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function receiveWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_,\n        bytes32 r_,\n        bytes32 vs_\n    ) external {\n        _revertIfInvalidSignature(\n            from_,\n            _getReceiveWithAuthorizationDigest(from_, to_, value_, validAfter_, validBefore_, nonce_),\n            r_,\n            vs_\n        );\n\n        _receiveWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function receiveWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_,\n        uint8 v_,\n        bytes32 r_,\n        bytes32 s_\n    ) external {\n        _revertIfInvalidSignature(\n            from_,\n            _getReceiveWithAuthorizationDigest(from_, to_, value_, validAfter_, validBefore_, nonce_),\n            v_,\n            r_,\n            s_\n        );\n\n        _receiveWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function cancelAuthorization(address authorizer_, bytes32 nonce_, bytes memory signature_) external {\n        _revertIfInvalidSignature(authorizer_, _getCancelAuthorizationDigest(authorizer_, nonce_), signature_);\n        _cancelAuthorization(authorizer_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function cancelAuthorization(address authorizer_, bytes32 nonce_, bytes32 r_, bytes32 vs_) external {\n        _revertIfInvalidSignature(authorizer_, _getCancelAuthorizationDigest(authorizer_, nonce_), r_, vs_);\n        _cancelAuthorization(authorizer_, nonce_);\n    }\n\n    /// @inheritdoc IERC3009\n    function cancelAuthorization(address authorizer_, bytes32 nonce_, uint8 v_, bytes32 r_, bytes32 s_) external {\n        _revertIfInvalidSignature(authorizer_, _getCancelAuthorizationDigest(authorizer_, nonce_), v_, r_, s_);\n        _cancelAuthorization(authorizer_, nonce_);\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IERC3009\n    function authorizationState(address authorizer, bytes32 nonce) public view returns (bool) {\n        return _getERC3009StorageLocation().authorizationState[authorizer][nonce];\n    }\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @dev   Common transfer function used by `transferWithAuthorization` and `_receiveWithAuthorization`.\n     * @param from_        Payer's address (Authorizer).\n     * @param to_          Payee's address.\n     * @param value_       Amount to be transferred.\n     * @param validAfter_  The time after which this is valid (unix time).\n     * @param validBefore_ The time before which this is valid (unix time).\n     * @param nonce_       Unique nonce.\n     */\n    function _transferWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_\n    ) internal {\n        if (block.timestamp <= validAfter_) revert AuthorizationNotYetValid(block.timestamp, validAfter_);\n        if (block.timestamp >= validBefore_) revert AuthorizationExpired(block.timestamp, validBefore_);\n\n        _revertIfAuthorizationAlreadyUsed(from_, nonce_);\n\n        _getERC3009StorageLocation().authorizationState[from_][nonce_] = true;\n\n        emit AuthorizationUsed(from_, nonce_);\n\n        _transfer(from_, to_, value_);\n    }\n\n    /**\n     * @dev   Common receive function used by `receiveWithAuthorization`.\n     * @param from_        Payer's address (Authorizer).\n     * @param to_          Payee's address.\n     * @param value_       Amount to be transferred.\n     * @param validAfter_  The time after which this is valid (unix time).\n     * @param validBefore_ The time before which this is valid (unix time).\n     * @param nonce_       Unique nonce.\n     */\n    function _receiveWithAuthorization(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_\n    ) internal {\n        if (msg.sender != to_) revert CallerMustBePayee(msg.sender, to_);\n\n        _transferWithAuthorization(from_, to_, value_, validAfter_, validBefore_, nonce_);\n    }\n\n    /**\n     * @dev   Common cancel function used by `cancelAuthorization`.\n     * @param authorizer_ Authorizer's address.\n     * @param nonce_      Nonce of the authorization.\n     */\n    function _cancelAuthorization(address authorizer_, bytes32 nonce_) internal {\n        _revertIfAuthorizationAlreadyUsed(authorizer_, nonce_);\n\n        _getERC3009StorageLocation().authorizationState[authorizer_][nonce_] = true;\n\n        emit AuthorizationCanceled(authorizer_, nonce_);\n    }\n\n    /**\n     * @dev   Internal ERC20 transfer function that needs to be implemented by the inheriting contract.\n     * @param sender_    The sender's address.\n     * @param recipient_ The recipient's address.\n     * @param amount_    The amount to be transferred.\n     */\n    function _transfer(address sender_, address recipient_, uint256 amount_) internal virtual;\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @dev    Returns the internal EIP-712 digest of a transferWithAuthorization call.\n     * @param  from_        Payer's address (Authorizer).\n     * @param  to_          Payee's address.\n     * @param  value_       Amount to be transferred.\n     * @param  validAfter_  The time after which this is valid (unix time).\n     * @param  validBefore_ The time before which this is valid (unix time).\n     * @param  nonce_       Unique nonce.\n     * @return The internal EIP-712 digest.\n     */\n    function _getTransferWithAuthorizationDigest(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_\n    ) internal view returns (bytes32) {\n        return\n            _getDigest(\n                keccak256(\n                    abi.encode(\n                        TRANSFER_WITH_AUTHORIZATION_TYPEHASH,\n                        from_,\n                        to_,\n                        value_,\n                        validAfter_,\n                        validBefore_,\n                        nonce_\n                    )\n                )\n            );\n    }\n\n    /**\n     * @dev    Returns the internal EIP-712 digest of a receiveWithAuthorization call.\n     * @param  from_        Payer's address (Authorizer).\n     * @param  to_          Payee's address.\n     * @param  value_       Amount to be transferred.\n     * @param  validAfter_  The time after which this is valid (unix time).\n     * @param  validBefore_ The time before which this is valid (unix time).\n     * @param  nonce_       Unique nonce.\n     * @return The internal EIP-712 digest.\n     */\n    function _getReceiveWithAuthorizationDigest(\n        address from_,\n        address to_,\n        uint256 value_,\n        uint256 validAfter_,\n        uint256 validBefore_,\n        bytes32 nonce_\n    ) internal view returns (bytes32) {\n        return\n            _getDigest(\n                keccak256(\n                    abi.encode(\n                        RECEIVE_WITH_AUTHORIZATION_TYPEHASH,\n                        from_,\n                        to_,\n                        value_,\n                        validAfter_,\n                        validBefore_,\n                        nonce_\n                    )\n                )\n            );\n    }\n\n    /**\n     * @dev    Returns the internal EIP-712 digest of a cancelAuthorization call.\n     * @param  authorizer_ Authorizer's address.\n     * @param  nonce_      Nonce of the authorization.\n     * @return The internal EIP-712 digest.\n     */\n    function _getCancelAuthorizationDigest(address authorizer_, bytes32 nonce_) internal view returns (bytes32) {\n        return _getDigest(keccak256(abi.encode(CANCEL_AUTHORIZATION_TYPEHASH, authorizer_, nonce_)));\n    }\n\n    /**\n     * @dev   Reverts if the authorization is already used.\n     * @param authorizer_ The authorizer's address.\n     * @param nonce_      The nonce of the authorization.\n     */\n    function _revertIfAuthorizationAlreadyUsed(address authorizer_, bytes32 nonce_) internal view {\n        if (authorizationState(authorizer_, nonce_)) revert AuthorizationAlreadyUsed(authorizer_, nonce_);\n    }\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.20;\n\nimport {IAccessControl} from \"@openzeppelin/contracts/access/IAccessControl.sol\";\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {ERC165Upgradeable} from \"../utils/introspection/ERC165Upgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```solidity\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```solidity\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}\n * to enforce additional security measures for this role.\n */\nabstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControl, ERC165Upgradeable {\n    struct RoleData {\n        mapping(address account => bool) hasRole;\n        bytes32 adminRole;\n    }\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n\n    /// @custom:storage-location erc7201:openzeppelin.storage.AccessControl\n    struct AccessControlStorage {\n        mapping(bytes32 role => RoleData) _roles;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.AccessControl\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant AccessControlStorageLocation = 0x02dd7bc7dec4dceedda775e58dd541e08a116c6c53815c0bd028192f7b626800;\n\n    function _getAccessControlStorage() private pure returns (AccessControlStorage storage $) {\n        assembly {\n            $.slot := AccessControlStorageLocation\n        }\n    }\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with an {AccessControlUnauthorizedAccount} error including the required role.\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    function __AccessControl_init() internal onlyInitializing {\n    }\n\n    function __AccessControl_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].hasRole[account];\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`\n     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`\n     * is missing `role`.\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert AccessControlUnauthorizedAccount(account, role);\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        return $._roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `callerConfirmation`.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function renounceRole(bytes32 role, address callerConfirmation) public virtual {\n        if (callerConfirmation != _msgSender()) {\n            revert AccessControlBadConfirmation();\n        }\n\n        _revokeRole(role, callerConfirmation);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        $._roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleGranted} event.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (!hasRole(role, account)) {\n            $._roles[role].hasRole[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.\n     *\n     * Internal function without access restriction.\n     *\n     * May emit a {RoleRevoked} event.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {\n        AccessControlStorage storage $ = _getAccessControlStorage();\n        if (hasRole(role, account)) {\n            $._roles[role].hasRole[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"},{"file_path":"lib/common/src/interfaces/IERC712.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity >=0.8.20 <0.9.0;\n\n/**\n * @title  Typed structured data hashing and signing via EIP-712.\n * @author M^0 Labs\n * @dev    The interface as defined by EIP-712: https://eips.ethereum.org/EIPS/eip-712\n */\ninterface IERC712 {\n    /* ============ Custom Errors ============ */\n\n    /// @notice Revert message when an invalid signature is detected.\n    error InvalidSignature();\n\n    /// @notice Revert message when a signature with invalid length is detected.\n    error InvalidSignatureLength();\n\n    /// @notice Revert message when the S portion of a signature is invalid.\n    error InvalidSignatureS();\n\n    /// @notice Revert message when the V portion of a signature is invalid.\n    error InvalidSignatureV();\n\n    /**\n     * @notice Revert message when a signature is being used beyond its deadline (i.e. expiry).\n     * @param  deadline  The last timestamp where the signature is still valid.\n     * @param  timestamp The current timestamp.\n     */\n    error SignatureExpired(uint256 deadline, uint256 timestamp);\n\n    /// @notice Revert message when a recovered signer does not match the account being purported to have signed.\n    error SignerMismatch();\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice Returns the EIP712 domain separator used in the encoding of a signed digest.\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},{"file_path":"src/components/freezable/Freezable.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.26;\n\nimport { AccessControlUpgradeable } from \"../../../lib/common/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol\";\n\nimport { IFreezable } from \"./IFreezable.sol\";\n\nabstract contract FreezableStorageLayout {\n    /// @custom:storage-location erc7201:M0.storage.Freezable\n    struct FreezableStorageStruct {\n        mapping(address account => bool isFrozen) isFrozen;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"M0.storage.Freezable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant _FREEZABLE_STORAGE_LOCATION =\n        0x2fd5767309dce890c526ace85d7fe164825199d7dcd99c33588befc51b32ce00;\n\n    function _getFreezableStorageLocation() internal pure returns (FreezableStorageStruct storage $) {\n        assembly {\n            $.slot := _FREEZABLE_STORAGE_LOCATION\n        }\n    }\n}\n\n/**\n * @title Freezable\n * @notice Upgradeable contract that allows for the freezing of accounts.\n * @dev This contract is used to prevent certain accounts from interacting with the contract.\n * @author M0 Labs\n */\nabstract contract Freezable is IFreezable, FreezableStorageLayout, AccessControlUpgradeable {\n    /* ============ Variables ============ */\n\n    /// @inheritdoc IFreezable\n    bytes32 public constant FREEZE_MANAGER_ROLE = keccak256(\"FREEZE_MANAGER_ROLE\");\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @notice Initializes the contract with the given freeze manager.\n     * @param freezeManager The address of a freeze manager.\n     */\n    function __Freezable_init(address freezeManager) internal onlyInitializing {\n        if (freezeManager == address(0)) revert ZeroFreezeManager();\n        _grantRole(FREEZE_MANAGER_ROLE, freezeManager);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IFreezable\n    function freeze(address account) external virtual onlyRole(FREEZE_MANAGER_ROLE) {\n        _freeze(_getFreezableStorageLocation(), account);\n    }\n\n    /// @inheritdoc IFreezable\n    function freezeAccounts(address[] calldata accounts) external virtual onlyRole(FREEZE_MANAGER_ROLE) {\n        FreezableStorageStruct storage $ = _getFreezableStorageLocation();\n        for (uint256 i; i < accounts.length; ++i) {\n            _freeze($, accounts[i]);\n        }\n    }\n\n    /// @inheritdoc IFreezable\n    function unfreeze(address account) external onlyRole(FREEZE_MANAGER_ROLE) {\n        _unfreeze(_getFreezableStorageLocation(), account);\n    }\n\n    /// @inheritdoc IFreezable\n    function unfreezeAccounts(address[] calldata accounts) external onlyRole(FREEZE_MANAGER_ROLE) {\n        FreezableStorageStruct storage $ = _getFreezableStorageLocation();\n\n        for (uint256 i; i < accounts.length; ++i) {\n            _unfreeze($, accounts[i]);\n        }\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IFreezable\n    function isFrozen(address account) public view returns (bool) {\n        return _getFreezableStorageLocation().isFrozen[account];\n    }\n\n    /* ============ Hooks For Internal Interactive Functions ============ */\n\n    /**\n     * @dev   Hook called before freezing an account.\n     * @param account   The account to be frozen.\n     */\n    function _beforeFreeze(address account) internal virtual {}\n\n    /**\n     * @dev    Hook called before unfreezing an account.\n     * @param  account   The account to be unfrozen.\n     */\n    function _beforeUnfreeze(address account) internal virtual {}\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @notice Internal function that freezes an account.\n     * @param $ The storage location of the freezable contract.\n     * @param account The account to freeze.\n     */\n    function _freeze(FreezableStorageStruct storage $, address account) internal {\n        // Return early if the account is already frozen\n        if ($.isFrozen[account]) return;\n\n        _beforeFreeze(account);\n\n        $.isFrozen[account] = true;\n\n        emit Frozen(account, block.timestamp);\n    }\n\n    /**\n     * @notice Internal function that unfreezes an account.\n     * @param $ The storage location of the freezable contract.\n     * @param account The account to unfreeze.\n     */\n    function _unfreeze(FreezableStorageStruct storage $, address account) internal {\n        // Return early if the account is not frozen\n        if (!$.isFrozen[account]) return;\n\n        _beforeUnfreeze(account);\n\n        $.isFrozen[account] = false;\n\n        emit Unfrozen(account, block.timestamp);\n    }\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @notice Internal function that reverts if an account is frozen.\n     * @dev Called by inheriting contracts to check if an account is frozen.\n     * @param $ The storage location of the freezable contract.\n     * @param account The account to check.\n     */\n    function _revertIfFrozen(FreezableStorageStruct storage $, address account) internal view {\n        if ($.isFrozen[account]) revert AccountFrozen(account);\n    }\n\n    /**\n     * @notice Internal function that reverts if an account is frozen.\n     * @dev Called by inheriting contracts to check if an account is frozen.\n     * @param account The account to check.\n     */\n    function _revertIfFrozen(address account) internal view {\n        if (_getFreezableStorageLocation().isFrozen[account]) revert AccountFrozen(account);\n    }\n\n    /**\n     * @notice Internal function that reverts if an account is not frozen.\n     * @dev Called by inheriting contracts to check if an account is not frozen.\n     * @param $ The storage location of the freezable contract.\n     * @param account The account to check.\n     */\n    function _revertIfNotFrozen(FreezableStorageStruct storage $, address account) internal view {\n        if (!$.isFrozen[account]) revert AccountNotFrozen(account);\n    }\n\n    /**\n     * @notice Internal function that reverts if an account is not frozen.\n     * @dev Called by inheriting contracts to check if an account is not frozen.\n     * @param account The account to check.\n     */\n    function _revertIfNotFrozen(address account) internal view {\n        if (!_getFreezableStorageLocation().isFrozen[account]) revert AccountNotFrozen(account);\n    }\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/contracts/utils/introspection/ERC165Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport {Initializable} from \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165 {\n    function __ERC165_init() internal onlyInitializing {\n    }\n\n    function __ERC165_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"src/components/pausable/Pausable.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.26;\n\nimport { AccessControlUpgradeable } from \"../../../lib/common/lib/openzeppelin-contracts-upgradeable/contracts/access/AccessControlUpgradeable.sol\";\nimport { PausableUpgradeable } from \"../../../lib/common/lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol\";\n\nimport { IPausable } from \"./IPausable.sol\";\n\n/**\n * @title Pausable\n * @notice Upgradeable contract that allows to pause the inheriting contract.\n * @dev Relies on PausableUpgradeable from OpenZeppelin for pause functionality.\n * @author M0 Labs\n */\nabstract contract Pausable is IPausable, AccessControlUpgradeable, PausableUpgradeable {\n    /* ============ Variables ============ */\n\n    /// @inheritdoc IPausable\n    bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n\n    /* ============ Initializer ============ */\n\n    /**\n     * @notice Initializes the contract with the given pauser.\n     * @param pauser The address of a pauser.\n     */\n    function __Pausable_init(address pauser) internal onlyInitializing {\n        if (pauser == address(0)) revert ZeroPauser();\n        _grantRole(PAUSER_ROLE, pauser);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IPausable\n    function pause() external onlyRole(PAUSER_ROLE) {\n        _beforePause();\n        _pause();\n    }\n\n    /// @inheritdoc IPausable\n    function unpause() external onlyRole(PAUSER_ROLE) {\n        _beforeUnpause();\n        _unpause();\n    }\n\n    /* ============ Hooks For Internal Interactive Functions ============ */\n\n    /**\n     * @dev   Hook called before pausing the contract.\n     */\n    function _beforePause() internal virtual {}\n\n    /**\n     * @dev    Hook called before unpausing the contract.\n     */\n    function _beforeUnpause() internal virtual {}\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"lib/common/lib/openzeppelin-contracts-upgradeable/contracts/utils/PausableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Pausable.sol)\n\npragma solidity ^0.8.20;\n\nimport {ContextUpgradeable} from \"../utils/ContextUpgradeable.sol\";\nimport {Initializable} from \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /// @custom:storage-location erc7201:openzeppelin.storage.Pausable\n    struct PausableStorage {\n        bool _paused;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Pausable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant PausableStorageLocation = 0xcd5ed15c6e187e77e9aee88184c21f4f2182ab5827cb3b7e07fbedcd63f03300;\n\n    function _getPausableStorage() private pure returns (PausableStorage storage $) {\n        assembly {\n            $.slot := PausableStorageLocation\n        }\n    }\n\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    /**\n     * @dev The operation failed because the contract is paused.\n     */\n    error EnforcedPause();\n\n    /**\n     * @dev The operation failed because the contract is not paused.\n     */\n    error ExpectedPause();\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    function __Pausable_init() internal onlyInitializing {\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n    }\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        PausableStorage storage $ = _getPausableStorage();\n        return $._paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        if (paused()) {\n            revert EnforcedPause();\n        }\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        if (!paused()) {\n            revert ExpectedPause();\n        }\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        PausableStorage storage $ = _getPausableStorage();\n        $._paused = false;\n        emit Unpaused(_msgSender());\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"mToken","type":"address"},{"internalType":"address","name":"swapFacility","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AccountFrozen","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AccountNotFrozen","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"AssetCapReached","type":"error"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationAlreadyUsed","type":"error"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"}],"name":"AuthorizationExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"}],"name":"AuthorizationNotYetValid","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"payee","type":"address"}],"name":"CallerMustBePayee","type":"error"},{"inputs":[],"name":"EarningIsDisabled","type":"error"},{"inputs":[],"name":"EarningIsEnabled","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InsufficientAmount","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"assetAvailable","type":"uint256"}],"name":"InsufficientAssetBacking","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amountExpected","type":"uint256"},{"internalType":"uint256","name":"amountReceived","type":"uint256"}],"name":"InsufficientAssetReceived","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"mAvailable","type":"uint256"}],"name":"InsufficientMBacking","type":"error"},{"inputs":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expectedNonce","type":"uint256"}],"name":"InvalidAccountNonce","type":"error"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"InvalidAsset","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"}],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"InvalidSignatureS","type":"error"},{"inputs":[],"name":"InvalidSignatureV","type":"error"},{"inputs":[],"name":"InvalidUInt240","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotSwapFacility","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"SignatureExpired","type":"error"},{"inputs":[],"name":"SignerMismatch","type":"error"},{"inputs":[],"name":"ZeroAdmin","type":"error"},{"inputs":[],"name":"ZeroAssetCapManager","type":"error"},{"inputs":[],"name":"ZeroFreezeManager","type":"error"},{"inputs":[],"name":"ZeroMToken","type":"error"},{"inputs":[],"name":"ZeroPauser","type":"error"},{"inputs":[],"name":"ZeroSwapFacility","type":"error"},{"inputs":[],"name":"ZeroYieldRecipient","type":"error"},{"inputs":[],"name":"ZeroYieldRecipientManager","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"cap","type":"uint256"}],"name":"AssetCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"mAmount","type":"uint256"}],"name":"AssetReplacedWithM","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"index","type":"uint128"}],"name":"EarningDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"index","type":"uint128"}],"name":"EarningEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Frozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"Unfrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"yield","type":"uint256"}],"name":"YieldClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"yieldRecipient","type":"address"}],"name":"YieldRecipientSet","type":"event"},{"inputs":[],"name":"ASSET_CAP_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FREEZE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"M_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAUSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECEIVE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"YIELD_RECIPIENT_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"assetBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"assetCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"assetDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer_","type":"address"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"vs_","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer_","type":"address"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer_","type":"address"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimYield","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentIndex","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableEarning","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields_","type":"bytes1"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"version_","type":"string"},{"internalType":"uint256","name":"chainId_","type":"uint256"},{"internalType":"address","name":"verifyingContract_","type":"address"},{"internalType":"bytes32","name":"salt_","type":"bytes32"},{"internalType":"uint256[]","name":"extensions_","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableEarning","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"freeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"freezeAccounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"yieldRecipient","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"assetCapManager","type":"address"},{"internalType":"address","name":"freezeManager","type":"address"},{"internalType":"address","name":"pauser","type":"address"},{"internalType":"address","name":"yieldRecipientManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"address","name":"yieldRecipient_","type":"address"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"freezeManager","type":"address"},{"internalType":"address","name":"yieldRecipientManager","type":"address"},{"internalType":"address","name":"pauser","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"isAllowedAsset","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"isAllowedToReplaceAssetWithM","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"isAllowedToUnwrap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"isAllowedToWrap","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isEarningEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isFrozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"validAfter_","type":"uint256"},{"internalType":"uint256","name":"validBefore_","type":"uint256"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"validAfter_","type":"uint256"},{"internalType":"uint256","name":"validBefore_","type":"uint256"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"vs_","type":"bytes32"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"validAfter_","type":"uint256"},{"internalType":"uint256","name":"validBefore_","type":"uint256"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"replaceAssetWithM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"setAssetCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"setYieldRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapFacility","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender_","type":"address"},{"internalType":"address","name":"recipient_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"validAfter_","type":"uint256"},{"internalType":"uint256","name":"validBefore_","type":"uint256"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"vs_","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"validAfter_","type":"uint256"},{"internalType":"uint256","name":"validBefore_","type":"uint256"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"bytes","name":"signature_","type":"bytes"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"address","name":"to_","type":"address"},{"internalType":"uint256","name":"value_","type":"uint256"},{"internalType":"uint256","name":"validAfter_","type":"uint256"},{"internalType":"uint256","name":"validBefore_","type":"uint256"},{"internalType":"bytes32","name":"nonce_","type":"bytes32"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"unfreeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"}],"name":"unfreezeAccounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"yield","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"yieldRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b000000000000000000000000b6807116b3b1b321a390594e31ecd6e0076f6278"}