{"file_path":"lib/protocol/src/MinterGateway.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { SignatureChecker } from \"../lib/common/src/libs/SignatureChecker.sol\";\n\nimport { ERC712Extended } from \"../lib/common/src/ERC712Extended.sol\";\nimport { UIntMath } from \"../lib/common/src/libs/UIntMath.sol\";\n\nimport { TTGRegistrarReader } from \"./libs/TTGRegistrarReader.sol\";\n\nimport { IContinuousIndexing } from \"./interfaces/IContinuousIndexing.sol\";\nimport { IMToken } from \"./interfaces/IMToken.sol\";\nimport { IMinterGateway } from \"./interfaces/IMinterGateway.sol\";\nimport { IRateModel } from \"./interfaces/IRateModel.sol\";\n\nimport { ContinuousIndexing } from \"./abstract/ContinuousIndexing.sol\";\nimport { ContinuousIndexingMath } from \"./libs/ContinuousIndexingMath.sol\";\n\n/*\n\n███╗   ███╗██╗███╗   ██╗████████╗███████╗██████╗      ██████╗  █████╗ ████████╗███████╗██╗    ██╗ █████╗ ██╗   ██╗\n████╗ ████║██║████╗  ██║╚══██╔══╝██╔════╝██╔══██╗    ██╔════╝ ██╔══██╗╚══██╔══╝██╔════╝██║    ██║██╔══██╗╚██╗ ██╔╝\n██╔████╔██║██║██╔██╗ ██║   ██║   █████╗  ██████╔╝    ██║  ███╗███████║   ██║   █████╗  ██║ █╗ ██║███████║ ╚████╔╝\n██║╚██╔╝██║██║██║╚██╗██║   ██║   ██╔══╝  ██╔══██╗    ██║   ██║██╔══██║   ██║   ██╔══╝  ██║███╗██║██╔══██║  ╚██╔╝\n██║ ╚═╝ ██║██║██║ ╚████║   ██║   ███████╗██║  ██║    ╚██████╔╝██║  ██║   ██║   ███████╗╚███╔███╔╝██║  ██║   ██║\n╚═╝     ╚═╝╚═╝╚═╝  ╚═══╝   ╚═╝   ╚══════╝╚═╝  ╚═╝     ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝ ╚══╝╚══╝ ╚═╝  ╚═╝   ╚═╝\n\n-->> Where money is born. <<--\n\n*/\n\n/**\n * @title  MinterGateway\n * @author M^0 Labs\n * @notice Minting Gateway of M Token for all approved by TTG and activated minters.\n */\ncontract MinterGateway is IMinterGateway, ContinuousIndexing, ERC712Extended {\n    /* ============ Structs ============ */\n\n    /**\n     * @notice Mint proposal struct.\n     * @param  id          The unique ID of the mint proposal.\n     * @param  createdAt   The timestamp at which the mint proposal was created.\n     * @param  destination The address to mint M to.\n     * @param  amount      The amount of M to mint.\n     */\n    struct MintProposal {\n        // 1st slot\n        uint48 id;\n        uint40 createdAt;\n        address destination;\n        // 2nd slot\n        uint240 amount;\n    }\n\n    /**\n     * @notice Minter state struct.\n     * @param  isActive                Whether the minter is active or not.\n     * @param  isDeactivated           Whether the minter is deactivated or not.\n     * @param  collateral              The amount of collateral the minter has.\n     * @param  totalPendingRetrievals  The total amount of pending retrievals.\n     * @param  updateTimestamp         The timestamp at which the minter last updated their collateral.\n     * @param  penalizedUntilTimestamp The timestamp until which the minter is penalized.\n     * @param  frozenUntilTimestamp    The timestamp until which the minter is frozen.\n     * @param  latestProposedRetrievalTimestamp The timestamp at which the minter last proposed a retrieval.\n     */\n    struct MinterState {\n        // 1st slot\n        bool isActive;\n        bool isDeactivated;\n        uint240 collateral;\n        // 2nd slot\n        uint240 totalPendingRetrievals;\n        // 3rd slot\n        uint40 updateTimestamp;\n        uint40 penalizedUntilTimestamp;\n        uint40 frozenUntilTimestamp;\n        uint40 latestProposedRetrievalTimestamp;\n    }\n\n    /* ============ Variables ============ */\n\n    /// @inheritdoc IMinterGateway\n    uint16 public constant ONE = 10_000;\n\n    /// @inheritdoc IMinterGateway\n    uint32 public constant MAX_MINT_RATIO = 65_000;\n\n    /// @notice IMinterGateway\n    uint32 public constant MIN_UPDATE_COLLATERAL_INTERVAL = 3_600;\n\n    // solhint-disable-next-line max-line-length\n    /// @dev keccak256(\"UpdateCollateral(address minter,uint256 collateral,uint256[] retrievalIds,bytes32 metadataHash,uint256 timestamp)\")\n    /// @inheritdoc IMinterGateway\n    bytes32 public constant UPDATE_COLLATERAL_TYPEHASH =\n        0x22b57ca54bd15c6234b29e87aa1d76a0841b6e65e63d7acacef989de0bc3ff9e;\n\n    /// @inheritdoc IMinterGateway\n    address public immutable ttgRegistrar;\n\n    /// @inheritdoc IMinterGateway\n    address public immutable ttgVault;\n\n    /// @inheritdoc IMinterGateway\n    address public immutable mToken;\n\n    /// @inheritdoc IMinterGateway\n    uint240 public totalInactiveOwedM;\n\n    /// @inheritdoc IMinterGateway\n    uint112 public principalOfTotalActiveOwedM;\n\n    /// @dev Nonce used to generate unique mint proposal IDs.\n    uint48 internal _mintNonce;\n\n    /// @dev Nonce used to generate unique retrieval proposal IDs.\n    uint48 internal _retrievalNonce;\n\n    /// @dev The state of each minter, their collaterals, relevant timestamps, and total pending retrievals.\n    mapping(address minter => MinterState state) internal _minterStates;\n\n    /// @dev The mint proposals of minter (mint ID, creation timestamp, destination, amount).\n    mapping(address minter => MintProposal proposal) internal _mintProposals;\n\n    /// @dev The owed M of active and inactive minters (principal of active, inactive).\n    mapping(address minter => uint240 rawOwedM) internal _rawOwedM;\n\n    /// @dev The pending collateral retrievals of minter (retrieval ID, amount).\n    mapping(address minter => mapping(uint48 retrievalId => uint240 amount)) internal _pendingCollateralRetrievals;\n\n    /// @dev The last update signature timestamp of each validator for each minter.\n    mapping(address minter => mapping(address validator => uint256 timestamp)) internal _lastSignatureTimestamp;\n\n    /* ============ Modifiers ============ */\n\n    /**\n     * @notice Only allow active minter to call function.\n     * @param  minter_ The address of the minter to check.\n     */\n    modifier onlyActiveMinter(address minter_) {\n        _revertIfInactiveMinter(minter_);\n\n        _;\n    }\n\n    /// @notice Only allow approved validator in TTG to call function.\n    modifier onlyApprovedValidator() {\n        _revertIfNotApprovedValidator(msg.sender);\n\n        _;\n    }\n\n    /// @notice Only allow unfrozen minter to call function.\n    modifier onlyUnfrozenMinter() {\n        _revertIfFrozenMinter(msg.sender);\n\n        _;\n    }\n\n    /* ============ Constructor ============ */\n\n    /**\n     * @notice Constructor.\n     * @param  ttgRegistrar_ The address of the TTG Registrar contract.\n     * @param  mToken_        The address of the M Token.\n     */\n    constructor(address ttgRegistrar_, address mToken_) ContinuousIndexing() ERC712Extended(\"MinterGateway\") {\n        if ((ttgRegistrar = ttgRegistrar_) == address(0)) revert ZeroTTGRegistrar();\n        if ((ttgVault = TTGRegistrarReader.getVault(ttgRegistrar_)) == address(0)) revert ZeroTTGVault();\n        if ((mToken = mToken_) == address(0)) revert ZeroMToken();\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IMinterGateway\n    function updateCollateral(\n        uint256 collateral_,\n        uint256[] calldata retrievalIds_,\n        bytes32 metadataHash_,\n        address[] calldata validators_,\n        uint256[] calldata timestamps_,\n        bytes[] calldata signatures_\n    ) external onlyActiveMinter(msg.sender) returns (uint40 minTimestamp_) {\n        if (validators_.length != signatures_.length || signatures_.length != timestamps_.length) {\n            revert SignatureArrayLengthsMismatch();\n        }\n\n        // Verify that enough valid signatures are provided, and get the minimum timestamp across all valid signatures.\n        minTimestamp_ = _verifyValidatorSignatures(\n            msg.sender,\n            collateral_,\n            retrievalIds_,\n            metadataHash_,\n            validators_,\n            timestamps_,\n            signatures_\n        );\n\n        _imposePenaltyIfMissedCollateralUpdates(msg.sender);\n\n        _imposePenaltyIfUndercollateralized(msg.sender, minTimestamp_);\n\n        uint240 safeCollateral_ = UIntMath.safe240(collateral_);\n        uint240 totalResolvedCollateralRetrieval_ = _resolvePendingRetrievals(msg.sender, retrievalIds_);\n\n        emit CollateralUpdated(\n            msg.sender,\n            safeCollateral_,\n            totalResolvedCollateralRetrieval_,\n            metadataHash_,\n            minTimestamp_\n        );\n\n        _updateCollateral(msg.sender, safeCollateral_, minTimestamp_);\n\n        // NOTE: Above functionality already has access to `currentIndex()`, and since the completion of the collateral\n        //       update can result in a new rate, we should update the index here to lock in that rate.\n        updateIndex();\n    }\n\n    /// @inheritdoc IMinterGateway\n    function proposeRetrieval(uint256 collateral_) external onlyActiveMinter(msg.sender) returns (uint48 retrievalId_) {\n        if (collateral_ == 0) revert ZeroRetrievalAmount();\n\n        unchecked {\n            retrievalId_ = ++_retrievalNonce;\n        }\n\n        MinterState storage minterState_ = _minterStates[msg.sender];\n        uint240 currentCollateral_ = minterState_.collateral;\n        uint240 safeCollateral_ = UIntMath.safe240(collateral_);\n        uint240 updatedTotalPendingRetrievals_ = minterState_.totalPendingRetrievals + safeCollateral_;\n\n        // NOTE: Revert if collateral is less than sum of all pending retrievals even if there is no owed M by minter.\n        if (currentCollateral_ < updatedTotalPendingRetrievals_) {\n            revert RetrievalsExceedCollateral(updatedTotalPendingRetrievals_, currentCollateral_);\n        }\n\n        minterState_.latestProposedRetrievalTimestamp = uint40(block.timestamp);\n        minterState_.totalPendingRetrievals = updatedTotalPendingRetrievals_;\n        _pendingCollateralRetrievals[msg.sender][retrievalId_] = safeCollateral_;\n\n        _revertIfUndercollateralized(msg.sender, 0);\n\n        emit RetrievalCreated(retrievalId_, msg.sender, safeCollateral_);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function proposeMint(\n        uint256 amount_,\n        address destination_\n    ) external onlyActiveMinter(msg.sender) onlyUnfrozenMinter returns (uint48 mintId_) {\n        if (amount_ == 0) revert ZeroMintAmount();\n        if (destination_ == address(0)) revert ZeroMintDestination();\n\n        uint240 safeAmount_ = UIntMath.safe240(amount_);\n\n        _revertIfUndercollateralized(msg.sender, safeAmount_); // Ensure minter remains sufficiently collateralized.\n\n        unchecked {\n            mintId_ = ++_mintNonce;\n        }\n\n        _mintProposals[msg.sender] = MintProposal(mintId_, uint40(block.timestamp), destination_, safeAmount_);\n\n        emit MintProposed(mintId_, msg.sender, safeAmount_, destination_);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function mintM(\n        uint256 mintId_\n    ) external onlyActiveMinter(msg.sender) onlyUnfrozenMinter returns (uint112 principalAmount_, uint240 amount_) {\n        MintProposal storage mintProposal_ = _mintProposals[msg.sender];\n\n        uint48 id_;\n        uint40 createdAt_;\n        address destination_;\n        (id_, createdAt_, destination_, amount_) = (\n            mintProposal_.id,\n            mintProposal_.createdAt,\n            mintProposal_.destination,\n            mintProposal_.amount\n        );\n\n        if (id_ != mintId_) revert InvalidMintProposal();\n\n        unchecked {\n            // Check that mint proposal is executable.\n            uint40 activeAt_ = createdAt_ + mintDelay();\n            if (block.timestamp < activeAt_) revert PendingMintProposal(activeAt_);\n\n            uint40 expiresAt_ = activeAt_ + mintTTL();\n            if (block.timestamp > expiresAt_) revert ExpiredMintProposal(expiresAt_);\n        }\n\n        _revertIfUndercollateralized(msg.sender, amount_); // Ensure minter remains sufficiently collateralized.\n\n        delete _mintProposals[msg.sender]; // Delete mint request.\n\n        // Adjust principal of active owed M for minter.\n        // NOTE: When minting a present amount, round the principal up in favor of the protocol.\n        principalAmount_ = _getPrincipalAmountRoundedUp(amount_);\n        uint112 principalOfTotalActiveOwedM_ = principalOfTotalActiveOwedM;\n\n        emit MintExecuted(id_, msg.sender, principalAmount_, amount_);\n\n        unchecked {\n            uint256 newPrincipalOfTotalActiveOwedM_ = uint256(principalOfTotalActiveOwedM_) + principalAmount_;\n\n            // As an edge case precaution, prevent a mint that, if all owed M (active and inactive) was converted to\n            // a principal active amount, would overflow the `uint112 principalOfTotalActiveOwedM`.\n            if (\n                // NOTE: Round the principal up for worst case.\n                newPrincipalOfTotalActiveOwedM_ + _getPrincipalAmountRoundedUp(totalInactiveOwedM) >= type(uint112).max\n            ) {\n                revert OverflowsPrincipalOfTotalOwedM();\n            }\n\n            principalOfTotalActiveOwedM = uint112(newPrincipalOfTotalActiveOwedM_);\n            _rawOwedM[msg.sender] += principalAmount_; // Treat rawOwedM as principal since minter is active.\n        }\n\n        IMToken(mToken).mint(destination_, amount_);\n\n        // NOTE: Above functionality already has access to `currentIndex()`, and since the completion of the mint\n        //       can result in a new rate, we should update the index here to lock in that rate.\n        updateIndex();\n    }\n\n    /// @inheritdoc IMinterGateway\n    function burnM(address minter_, uint256 maxAmount_) external returns (uint112 principalAmount_, uint240 amount_) {\n        (principalAmount_, amount_) = burnM(\n            minter_,\n            _getPrincipalAmountRoundedDown(UIntMath.safe240(maxAmount_)),\n            maxAmount_\n        );\n    }\n\n    /// @inheritdoc IMinterGateway\n    function burnM(\n        address minter_,\n        uint256 maxPrincipalAmount_,\n        uint256 maxAmount_\n    ) public returns (uint112 principalAmount_, uint240 amount_) {\n        if (maxPrincipalAmount_ == 0 || maxAmount_ == 0) revert ZeroBurnAmount();\n\n        MinterState storage minterState_ = _minterStates[minter_];\n        bool isActive_ = minterState_.isActive;\n\n        // Revert early if minter has not been activated.\n        if (!isActive_ && !minterState_.isDeactivated) revert InactiveMinter();\n\n        if (isActive_) {\n            // NOTE: Penalize only for missed collateral updates, not for undercollateralization.\n            // Undercollateralization within one update interval is forgiven.\n            _imposePenaltyIfMissedCollateralUpdates(minter_);\n\n            (principalAmount_, amount_) = _repayForActiveMinter(\n                minter_,\n                UIntMath.safe112(maxPrincipalAmount_),\n                UIntMath.safe240(maxAmount_)\n            );\n\n            emit BurnExecuted(minter_, principalAmount_, amount_, msg.sender);\n        } else {\n            amount_ = _repayForDeactivatedMinter(minter_, UIntMath.safe240(maxAmount_));\n\n            emit BurnExecuted(minter_, amount_, msg.sender);\n        }\n\n        IMToken(mToken).burn(msg.sender, amount_); // Burn actual M tokens\n\n        // NOTE: Above functionality already has access to `currentIndex()`, and since the completion of the burn\n        //       can result in a new rate, we should update the index here to lock in that rate.\n        updateIndex();\n    }\n\n    /// @inheritdoc IMinterGateway\n    function cancelMint(address minter_, uint256 mintId_) external onlyApprovedValidator {\n        uint48 id_ = _mintProposals[minter_].id;\n\n        if (id_ != mintId_ || id_ == 0) revert InvalidMintProposal();\n\n        delete _mintProposals[minter_];\n\n        emit MintCanceled(id_, minter_, msg.sender);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function freezeMinter(address minter_) external onlyApprovedValidator returns (uint40 frozenUntil_) {\n        unchecked {\n            _minterStates[minter_].frozenUntilTimestamp = frozenUntil_ = uint40(block.timestamp) + minterFreezeTime();\n        }\n\n        emit MinterFrozen(minter_, frozenUntil_);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function activateMinter(address minter_) external {\n        if (!isMinterApproved(minter_)) revert NotApprovedMinter();\n\n        MinterState storage minterState_ = _minterStates[minter_];\n\n        // NOTE: Once deactivated, a minter cannot be reactivated.\n        if (minterState_.isDeactivated) revert DeactivatedMinter();\n\n        minterState_.isActive = true;\n\n        emit MinterActivated(minter_, msg.sender);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function deactivateMinter(address minter_) external onlyActiveMinter(minter_) returns (uint240 inactiveOwedM_) {\n        if (isMinterApproved(minter_)) revert StillApprovedMinter();\n\n        _imposePenaltyIfMissedCollateralUpdates(minter_);\n\n        uint112 principalOfOwedM_ = principalOfActiveOwedMOf(minter_);\n\n        inactiveOwedM_ = _getPresentAmount(principalOfOwedM_);\n\n        unchecked {\n            // Treat rawOwedM as principal since minter is active.\n            principalOfTotalActiveOwedM -= principalOfOwedM_;\n            totalInactiveOwedM += inactiveOwedM_;\n        }\n\n        emit MinterDeactivated(minter_, inactiveOwedM_, msg.sender);\n\n        // Reset reasonable aspects of minter's state\n        delete _minterStates[minter_];\n        delete _mintProposals[minter_];\n\n        // Deactivate minter.\n        _minterStates[minter_].isDeactivated = true;\n\n        _rawOwedM[minter_] = inactiveOwedM_; // Treat rawOwedM as inactive owed M since minter is now inactive.\n\n        // NOTE: Above functionality already has access to `currentIndex()`, and since the completion of the\n        //       deactivation can result in a new rate, we should update the index here to lock in that rate.\n        updateIndex();\n    }\n\n    /// @inheritdoc IContinuousIndexing\n    function updateIndex() public override(IContinuousIndexing, ContinuousIndexing) returns (uint128 index_) {\n        // NOTE: Since the currentIndex of the Minter Gateway and mToken are constant through this context's execution\n        //       (the block.timestamp is not changing) we can compute excessOwedM without updating the mToken index.\n        uint240 excessOwedM_ = excessOwedM();\n\n        if (excessOwedM_ > 0) IMToken(mToken).mint(ttgVault, excessOwedM_); // Mint M to TTG Vault.\n\n        // NOTE: Above functionality already has access to `currentIndex()`, and since the completion of the collateral\n        //       update can result in a new rate, we should update the index here to lock in that rate.\n        // NOTE: With the current rate models, the minter rate does not depend on anything in the Minter Gateway\n        //       or mToken, so we can update the minter rate and index here.\n        index_ = super.updateIndex(); // Update minter index and rate.\n\n        // NOTE: Given the current implementation of the mToken transfers and its rate model, while it is possible for\n        //       the above mint to already have updated the mToken index if M was minted to an earning account, we want\n        //       to ensure the rate provided by the mToken's rate model is locked in.\n        IMToken(mToken).updateIndex(); // Update earning index and rate.\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IMinterGateway\n    function totalActiveOwedM() public view returns (uint240) {\n        return _getPresentAmount(principalOfTotalActiveOwedM);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function totalOwedM() external view returns (uint240) {\n        unchecked {\n            // NOTE: This can never overflow since the `mint` functions caps the principal of total owed M (active and\n            //       inactive) to `type(uint112).max`. Thus, there can never be enough inactive owed M (which is an\n            //       accumulations principal of active owed M values converted to present values at previous and lower\n            //       indices) or active owed M to overflow this.\n            return totalActiveOwedM() + totalInactiveOwedM;\n        }\n    }\n\n    /// @inheritdoc IMinterGateway\n    function excessOwedM() public view returns (uint240 excessOwedM_) {\n        // NOTE: Can safely cast to `uint240` since we know M Token totalSupply constraints.\n        uint240 totalMSupply_ = uint240(IMToken(mToken).totalSupply());\n\n        uint240 totalOwedM_ = _getPresentAmountRoundedDown(principalOfTotalActiveOwedM, currentIndex()) +\n            totalInactiveOwedM;\n\n        unchecked {\n            if (totalOwedM_ > totalMSupply_) return totalOwedM_ - totalMSupply_;\n        }\n    }\n\n    /// @inheritdoc IMinterGateway\n    function minterRate() external view returns (uint32) {\n        return _latestRate;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function isActiveMinter(address minter_) external view returns (bool) {\n        return _minterStates[minter_].isActive;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function isDeactivatedMinter(address minter_) external view returns (bool) {\n        return _minterStates[minter_].isDeactivated;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function isFrozenMinter(address minter_) external view returns (bool) {\n        return block.timestamp < _minterStates[minter_].frozenUntilTimestamp;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function principalOfActiveOwedMOf(address minter_) public view returns (uint112) {\n        // NOTE: This should also include the principal value of unavoidable penalities. But then it would be very, if\n        //       not impossible, to determine the `principalOfTotalActiveOwedM` to the same standards.\n        return\n            _minterStates[minter_].isActive\n                ? uint112(_rawOwedM[minter_]) // Treat rawOwedM as principal since minter is active.\n                : 0;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function activeOwedMOf(address minter_) public view returns (uint240) {\n        // NOTE: This should also include the present value of unavoidable penalities. But then it would be very, if\n        //       not impossible, to determine the `totalActiveOwedM` to the same standards.\n        return\n            _minterStates[minter_].isActive\n                ? _getPresentAmount(uint112(_rawOwedM[minter_])) // Treat rawOwedM as principal since minter is active.\n                : 0;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function maxAllowedActiveOwedMOf(address minter_) public view returns (uint256) {\n        // NOTE: Since `mintRatio()` is capped at 650% (i.e. 65_000) this cannot overflow.\n        unchecked {\n            return _minterStates[minter_].isActive ? (uint256(collateralOf(minter_)) * mintRatio()) / ONE : 0;\n        }\n    }\n\n    /// @inheritdoc IMinterGateway\n    function inactiveOwedMOf(address minter_) public view returns (uint240) {\n        // Treat rawOwedM as present amount since minter is inactive.\n        return _minterStates[minter_].isActive ? 0 : _rawOwedM[minter_];\n    }\n\n    /// @inheritdoc IMinterGateway\n    function collateralOf(address minter_) public view returns (uint240) {\n        // If collateral was not updated by the deadline, assume that minter's collateral is zero.\n        if (block.timestamp >= collateralExpiryTimestampOf(minter_)) return 0;\n\n        MinterState storage minterState_ = _minterStates[minter_];\n        uint240 totalPendingRetrievals_ = minterState_.totalPendingRetrievals;\n        uint240 collateral_ = minterState_.collateral;\n\n        // If the minter's total pending retrievals is greater than their collateral, then their collateral is zero.\n        if (totalPendingRetrievals_ >= collateral_) return 0;\n\n        unchecked {\n            return collateral_ - totalPendingRetrievals_;\n        }\n    }\n\n    /// @inheritdoc IMinterGateway\n    function collateralUpdateTimestampOf(address minter_) external view returns (uint40) {\n        return _minterStates[minter_].updateTimestamp;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function collateralPenaltyDeadlineOf(address minter_) external view returns (uint40) {\n        MinterState storage minterState_ = _minterStates[minter_];\n        uint32 updateCollateralInterval_ = updateCollateralInterval();\n\n        (, uint40 missedUntil_) = _getMissedCollateralUpdateParameters(\n            minterState_.updateTimestamp,\n            minterState_.penalizedUntilTimestamp,\n            updateCollateralInterval_\n        );\n\n        return missedUntil_ + updateCollateralInterval_;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function collateralExpiryTimestampOf(address minter_) public view returns (uint40) {\n        unchecked {\n            return _minterStates[minter_].updateTimestamp + updateCollateralInterval();\n        }\n    }\n\n    /// @inheritdoc IMinterGateway\n    function penalizedUntilOf(address minter_) external view returns (uint40) {\n        return _minterStates[minter_].penalizedUntilTimestamp;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function latestProposedRetrievalTimestampOf(address minter_) external view returns (uint40) {\n        return _minterStates[minter_].latestProposedRetrievalTimestamp;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function getLastSignatureTimestamp(address minter_, address validator_) external view returns (uint256) {\n        return _lastSignatureTimestamp[minter_][validator_];\n    }\n\n    /// @inheritdoc IMinterGateway\n    function getUpdateCollateralDigest(\n        address minter_,\n        uint256 collateral_,\n        uint256[] calldata retrievalIds_,\n        bytes32 metadataHash_,\n        uint256 timestamp_\n    ) external view returns (bytes32) {\n        return _getUpdateCollateralDigest(minter_, collateral_, retrievalIds_, metadataHash_, timestamp_);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function mintProposalOf(\n        address minter_\n    ) external view returns (uint48 mintId_, uint40 createdAt_, address destination_, uint240 amount_) {\n        mintId_ = _mintProposals[minter_].id;\n        createdAt_ = _mintProposals[minter_].createdAt;\n        destination_ = _mintProposals[minter_].destination;\n        amount_ = _mintProposals[minter_].amount;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function pendingCollateralRetrievalOf(address minter_, uint256 retrievalId_) external view returns (uint240) {\n        return\n            _minterStates[minter_].isDeactivated\n                ? 0\n                : _pendingCollateralRetrievals[minter_][UIntMath.safe48(retrievalId_)];\n    }\n\n    /// @inheritdoc IMinterGateway\n    function totalPendingCollateralRetrievalOf(address minter_) external view returns (uint240) {\n        return _minterStates[minter_].isDeactivated ? 0 : _minterStates[minter_].totalPendingRetrievals;\n    }\n\n    /// @inheritdoc IMinterGateway\n    function frozenUntilOf(address minter_) external view returns (uint40) {\n        return _minterStates[minter_].frozenUntilTimestamp;\n    }\n\n    /* ============ TTG Registrar Reader Functions ============ */\n\n    /// @inheritdoc IMinterGateway\n    function isMinterApproved(address minter_) public view returns (bool) {\n        return TTGRegistrarReader.isApprovedMinter(ttgRegistrar, minter_);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function isValidatorApproved(address validator_) public view returns (bool) {\n        return TTGRegistrarReader.isApprovedValidator(ttgRegistrar, validator_);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function updateCollateralInterval() public view returns (uint32) {\n        return\n            UIntMath.max32(\n                UIntMath.bound32(TTGRegistrarReader.getUpdateCollateralInterval(ttgRegistrar)),\n                MIN_UPDATE_COLLATERAL_INTERVAL\n            );\n    }\n\n    /// @inheritdoc IMinterGateway\n    function updateCollateralValidatorThreshold() public view returns (uint256) {\n        return TTGRegistrarReader.getUpdateCollateralValidatorThreshold(ttgRegistrar);\n    }\n\n    /// @inheritdoc IMinterGateway\n    function mintRatio() public view returns (uint32) {\n        // NOTE: It is possible for the mint ratio to be greater than 100%, but capped at 650%.\n        return UIntMath.min32(MAX_MINT_RATIO, UIntMath.bound32(TTGRegistrarReader.getMintRatio(ttgRegistrar)));\n    }\n\n    /// @inheritdoc IMinterGateway\n    function mintDelay() public view returns (uint32) {\n        return UIntMath.bound32(TTGRegistrarReader.getMintDelay(ttgRegistrar));\n    }\n\n    /// @inheritdoc IMinterGateway\n    function mintTTL() public view returns (uint32) {\n        return UIntMath.bound32(TTGRegistrarReader.getMintTTL(ttgRegistrar));\n    }\n\n    /// @inheritdoc IMinterGateway\n    function minterFreezeTime() public view returns (uint32) {\n        return UIntMath.bound32(TTGRegistrarReader.getMinterFreezeTime(ttgRegistrar));\n    }\n\n    /// @inheritdoc IMinterGateway\n    function penaltyRate() public view returns (uint32) {\n        return UIntMath.bound32(TTGRegistrarReader.getPenaltyRate(ttgRegistrar));\n    }\n\n    /// @inheritdoc IMinterGateway\n    function rateModel() public view returns (address) {\n        return TTGRegistrarReader.getMinterRateModel(ttgRegistrar);\n    }\n\n    /// @inheritdoc IContinuousIndexing\n    function currentIndex() public view override(ContinuousIndexing, IContinuousIndexing) returns (uint128) {\n        // NOTE: Safe to use unchecked here, since `block.timestamp` is always greater than `latestUpdateTimestamp`.\n        unchecked {\n            return\n                // NOTE: Cap the index to `type(uint128).max` to prevent overflow in present value math.\n                UIntMath.bound128(\n                    ContinuousIndexingMath.multiplyIndicesUp(\n                        latestIndex,\n                        ContinuousIndexingMath.getContinuousIndex(\n                            ContinuousIndexingMath.convertFromBasisPoints(_latestRate),\n                            uint32(block.timestamp - latestUpdateTimestamp)\n                        )\n                    )\n                );\n        }\n    }\n\n    /* ============ Internal Interactive Functions ============ */\n\n    /**\n     * @dev    Imposes penalty on an active minter. Calling this for an inactive minter will break accounting.\n     * @param  minter_                 The address of the minter.\n     * @param  principalOfPenaltyBase_ The principal of the base for penalization.\n     * @return The principal of the imposed penalty.\n     */\n    function _imposePenalty(address minter_, uint152 principalOfPenaltyBase_) internal returns (uint112) {\n        if (principalOfPenaltyBase_ == 0) return 0;\n\n        uint32 penaltyRate_ = penaltyRate();\n\n        if (penaltyRate_ == 0) return 0;\n\n        unchecked {\n            uint256 penaltyPrincipal_ = (uint256(principalOfPenaltyBase_) * penaltyRate_) / ONE;\n\n            // As an edge case precaution, cap the penalty principal such that the resulting principal of total active\n            // owed M plus the penalty principal is not greater than the max uint112.\n            uint256 newPrincipalOfTotalActiveOwedM_ = principalOfTotalActiveOwedM + penaltyPrincipal_;\n\n            if (newPrincipalOfTotalActiveOwedM_ > type(uint112).max) {\n                penaltyPrincipal_ = type(uint112).max - principalOfTotalActiveOwedM;\n                newPrincipalOfTotalActiveOwedM_ = type(uint112).max;\n            }\n\n            // Calculate and add penalty principal to total minter's principal of active owed M\n            principalOfTotalActiveOwedM = uint112(newPrincipalOfTotalActiveOwedM_);\n\n            _rawOwedM[minter_] += uint112(penaltyPrincipal_); // Treat rawOwedM as principal since minter is active.\n\n            return uint112(penaltyPrincipal_);\n        }\n    }\n\n    /**\n     * @dev   Imposes penalty if minter missed collateral updates.\n     * @param minter_ The address of the minter.\n     */\n    function _imposePenaltyIfMissedCollateralUpdates(address minter_) internal {\n        uint112 principalOfActiveOwedM_ = principalOfActiveOwedMOf(minter_);\n\n        if (principalOfActiveOwedM_ == 0) return;\n\n        MinterState storage minterState_ = _minterStates[minter_];\n\n        (uint40 missedIntervals_, uint40 missedUntil_) = _getMissedCollateralUpdateParameters(\n            minterState_.updateTimestamp,\n            minterState_.penalizedUntilTimestamp,\n            updateCollateralInterval()\n        );\n\n        if (missedIntervals_ == 0) return;\n\n        // Save until when the minter has been penalized for missed intervals to prevent double penalizing them.\n        minterState_.penalizedUntilTimestamp = missedUntil_;\n\n        uint112 penaltyPrincipal_ = _imposePenalty(minter_, uint152(principalOfActiveOwedM_) * missedIntervals_);\n\n        if (penaltyPrincipal_ == 0) return;\n\n        emit MissedIntervalsPenaltyImposed(minter_, missedIntervals_, _getPresentAmount(penaltyPrincipal_));\n    }\n\n    /**\n     * @dev   Imposes penalty if minter is undercollateralized.\n     * @param minter_       The address of the minter.\n     * @param newTimestamp_ The timestamp of the collateral update.\n     */\n    function _imposePenaltyIfUndercollateralized(address minter_, uint40 newTimestamp_) internal {\n        uint112 principalOfActiveOwedM_ = principalOfActiveOwedMOf(minter_);\n\n        if (principalOfActiveOwedM_ == 0) return;\n\n        uint256 maxAllowedActiveOwedM_ = maxAllowedActiveOwedMOf(minter_);\n\n        // If the minter's max allowed active owed M is greater than `type(uint240).max`, then it's definitely greater\n        // than the max possible active owed M for the minter, which is capped at `type(uint240).max`.\n        if (maxAllowedActiveOwedM_ >= type(uint240).max) return;\n\n        // NOTE: Round the principal down in favor of the protocol since this is a max applied to the minter.\n        uint112 principalOfMaxAllowedActiveOwedM_ = _getPrincipalAmountRoundedDown(uint240(maxAllowedActiveOwedM_));\n\n        // If the minter is not undercollateralized, then no penalty is imposed.\n        if (principalOfMaxAllowedActiveOwedM_ >= principalOfActiveOwedM_) return;\n\n        MinterState storage minterState_ = _minterStates[minter_];\n\n        uint40 penalizeFrom_ = UIntMath.max40(minterState_.updateTimestamp, minterState_.penalizedUntilTimestamp);\n\n        if (newTimestamp_ <= penalizeFrom_) return;\n\n        unchecked {\n            uint40 timeSpan_ = newTimestamp_ - penalizeFrom_;\n\n            uint112 principalOfExcessOwedM_ = principalOfActiveOwedM_ - principalOfMaxAllowedActiveOwedM_;\n\n            // NOTE: `newTimestamp_ - penalizeFrom_` will never be larger than `updateCollateralInterval_` since this\n            //       function is only called after `_imposePenaltyIfMissedCollateralUpdates`, which ensures that the\n            //       `penalizedUntilTimestamp` is within one `updateCollateralInterval_` of the `newTimestamp_`.\n            //\n            // NOTE: `updateCollateralInterval()` never equals 0, so the division is safe.\n            //       Its minimum is capped at `MIN_UPDATE_COLLATERAL_INTERVAL`.\n            uint112 penaltyPrincipal_ = _imposePenalty(\n                minter_,\n                (principalOfExcessOwedM_ * timeSpan_) / updateCollateralInterval()\n            );\n\n            if (penaltyPrincipal_ == 0) return;\n\n            emit UndercollateralizedPenaltyImposed(\n                minter_,\n                _getPresentAmount(principalOfExcessOwedM_),\n                timeSpan_,\n                _getPresentAmount(penaltyPrincipal_)\n            );\n        }\n    }\n\n    /**\n     * @dev    Repays active minter's owed M.\n     * @param  minter_             The address of the minter.\n     * @param  maxPrincipalAmount_ The maximum principal amount of active owed M to repay.\n     * @param  maxAmount_          The maximum amount of active owed M to repay.\n     * @return principalAmount_    The principal amount of active owed M that was actually repaid.\n     * @return amount_             The amount of active owed M that was actually repaid.\n     */\n    function _repayForActiveMinter(\n        address minter_,\n        uint112 maxPrincipalAmount_,\n        uint240 maxAmount_\n    ) internal returns (uint112 principalAmount_, uint240 amount_) {\n        principalAmount_ = UIntMath.min112(principalOfActiveOwedMOf(minter_), maxPrincipalAmount_);\n        amount_ = _getPresentAmount(principalAmount_);\n\n        if (amount_ > maxAmount_) revert ExceedsMaxRepayAmount(amount_, maxAmount_);\n\n        unchecked {\n            // Treat rawOwedM as principal since `principalAmount_` would only be non-zero for an active minter.\n            _rawOwedM[minter_] -= principalAmount_;\n            principalOfTotalActiveOwedM -= principalAmount_;\n        }\n    }\n\n    /**\n     * @dev    Repays deactivated minter's owed M.\n     * @param  minter_    The address of the minter.\n     * @param  maxAmount_ The maximum amount of inactive owed M to repay.\n     * @return amount_    The amount of inactive owed M that was actually repaid.\n     */\n    function _repayForDeactivatedMinter(address minter_, uint240 maxAmount_) internal returns (uint240 amount_) {\n        amount_ = UIntMath.min240(inactiveOwedMOf(minter_), maxAmount_);\n\n        unchecked {\n            // Treat rawOwedM as present amount since `amount_` would only be non-zero for an inactive minter.\n            _rawOwedM[minter_] -= amount_;\n            totalInactiveOwedM -= amount_;\n        }\n    }\n\n    /**\n     * @dev    Resolves the collateral retrieval IDs and updates the total pending collateral retrieval amount.\n     * @param  minter_                           The address of the minter.\n     * @param  retrievalIds_                     The list of outstanding collateral retrieval IDs to resolve.\n     * @return totalResolvedCollateralRetrieval_ The total amount of collateral retrieval resolved.\n     */\n    function _resolvePendingRetrievals(\n        address minter_,\n        uint256[] calldata retrievalIds_\n    ) internal returns (uint240 totalResolvedCollateralRetrieval_) {\n        for (uint256 index_; index_ < retrievalIds_.length; ++index_) {\n            uint48 retrievalId_ = UIntMath.safe48(retrievalIds_[index_]);\n            uint240 pendingCollateralRetrieval_ = _pendingCollateralRetrievals[minter_][retrievalId_];\n\n            if (pendingCollateralRetrieval_ == 0) continue;\n\n            unchecked {\n                // NOTE: The `proposeRetrieval` function already ensures that the sum of all\n                // `_pendingCollateralRetrievals` is not larger than `type(uint240).max`.\n                totalResolvedCollateralRetrieval_ += pendingCollateralRetrieval_;\n            }\n\n            delete _pendingCollateralRetrievals[minter_][retrievalId_];\n\n            emit RetrievalResolved(retrievalId_, minter_);\n        }\n\n        unchecked {\n            // NOTE: The `proposeRetrieval` function already ensures that `totalPendingRetrievals` is the sum of all\n            // `_pendingCollateralRetrievals`.\n            _minterStates[minter_].totalPendingRetrievals -= totalResolvedCollateralRetrieval_;\n        }\n    }\n\n    /**\n     * @dev   Updates the collateral amount and update timestamp for the minter.\n     * @param minter_       The address of the minter.\n     * @param amount_       The amount of collateral.\n     * @param newTimestamp_ The timestamp of the collateral update.\n     */\n    function _updateCollateral(address minter_, uint240 amount_, uint40 newTimestamp_) internal {\n        MinterState storage minterState_ = _minterStates[minter_];\n\n        // The earliest allowed timestamp for a collateral update is the maximum of:\n        //   - the last update timestamp,\n        //   - the latest proposed retrieval timestamp, and\n        //   - the current timestamp minus the update collateral interval.\n        unchecked {\n            // NOTE: Cannot underflow since `min40` is applied when `updateCollateralInterval()` > `block.timestamp`.\n            uint40 earliestAllowedTimestamp_ = UIntMath.max40(\n                UIntMath.max40(minterState_.updateTimestamp, minterState_.latestProposedRetrievalTimestamp),\n                uint40(block.timestamp) - UIntMath.min40(updateCollateralInterval(), uint40(block.timestamp))\n            );\n\n            if (newTimestamp_ <= earliestAllowedTimestamp_) {\n                revert StaleCollateralUpdate(newTimestamp_, earliestAllowedTimestamp_);\n            }\n        }\n\n        minterState_.collateral = amount_;\n        minterState_.updateTimestamp = newTimestamp_;\n    }\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @dev    Returns the penalization base and the penalized until timestamp.\n     * @param  lastUpdateTimestamp_ The last timestamp at which the minter updated their collateral.\n     * @param  lastPenalizedUntil_  The timestamp before which the minter shouldn't be penalized for missed updates.\n     * @param  updateInterval_      The update collateral interval.\n     * @return missedIntervals_     The number of missed update intervals.\n     * @return missedUntil_         The timestamp until which `missedIntervals_` covers,\n     *                              even if `missedIntervals_` is 0.\n     */\n    function _getMissedCollateralUpdateParameters(\n        uint40 lastUpdateTimestamp_,\n        uint40 lastPenalizedUntil_,\n        uint32 updateInterval_\n    ) internal view returns (uint40 missedIntervals_, uint40 missedUntil_) {\n        uint40 penalizeFrom_ = UIntMath.max40(lastUpdateTimestamp_, lastPenalizedUntil_);\n\n        // If brand new minter then there is no missed interval charge at all.\n        if (lastUpdateTimestamp_ == 0) return (0, penalizeFrom_);\n\n        uint40 timeElapsed_ = uint40(block.timestamp) - penalizeFrom_;\n\n        if (timeElapsed_ < updateInterval_) return (0, penalizeFrom_);\n\n        unchecked {\n            // NOTE: `updateInterval_` never equals 0, so the division is safe.\n            //       Its minimum is capped at `MIN_UPDATE_COLLATERAL_INTERVAL`.\n            missedIntervals_ = timeElapsed_ / updateInterval_;\n\n            // NOTE: Cannot really overflow a `uint40` since `missedIntervals_ * updateInterval_ <= timeElapsed_`.\n            missedUntil_ = penalizeFrom_ + (missedIntervals_ * updateInterval_);\n        }\n    }\n\n    /**\n     * @dev    Returns the present amount (rounded up) given the principal amount, using the current index.\n     *         All present amounts are rounded up in favor of the protocol, since they are owed.\n     * @param  principalAmount_ The principal amount.\n     * @return The present amount.\n     */\n    function _getPresentAmount(uint112 principalAmount_) internal view returns (uint240) {\n        return _getPresentAmountRoundedUp(principalAmount_, currentIndex());\n    }\n\n    /**\n     * @dev    Returns the EIP-712 digest for updateCollateral method.\n     * @param  minter_       The address of the minter.\n     * @param  collateral_   The amount of collateral.\n     * @param  retrievalIds_ The list of outstanding collateral retrieval IDs to resolve.\n     * @param  metadataHash_ The hash of metadata of the collateral update, reserved for future informational use.\n     * @param  timestamp_    The timestamp of the collateral update.\n     * @return The EIP-712 digest.\n     */\n    function _getUpdateCollateralDigest(\n        address minter_,\n        uint256 collateral_,\n        uint256[] calldata retrievalIds_,\n        bytes32 metadataHash_,\n        uint256 timestamp_\n    ) internal view returns (bytes32) {\n        return\n            _getDigest(\n                keccak256(\n                    abi.encode(\n                        UPDATE_COLLATERAL_TYPEHASH,\n                        minter_,\n                        collateral_,\n                        keccak256(abi.encodePacked(retrievalIds_)),\n                        metadataHash_,\n                        timestamp_\n                    )\n                )\n            );\n    }\n\n    /// @dev Returns the current rate from the rate model contract.\n    function _rate() internal view override returns (uint32 rate_) {\n        (bool success_, bytes memory returnData_) = rateModel().staticcall(\n            abi.encodeWithSelector(IRateModel.rate.selector)\n        );\n\n        rate_ = (success_ && returnData_.length >= 32) ? UIntMath.bound32(abi.decode(returnData_, (uint256))) : 0;\n    }\n\n    /**\n     * @dev   Reverts if minter is frozen by validator.\n     * @param minter_ The address of the minter\n     */\n    function _revertIfFrozenMinter(address minter_) internal view {\n        if (block.timestamp < _minterStates[minter_].frozenUntilTimestamp) revert FrozenMinter();\n    }\n\n    /**\n     * @dev   Reverts if minter is inactive.\n     * @param minter_ The address of the minter\n     */\n    function _revertIfInactiveMinter(address minter_) internal view {\n        if (!_minterStates[minter_].isActive) revert InactiveMinter();\n    }\n\n    /**\n     * @dev   Reverts if validator is not approved.\n     * @param validator_ The address of the validator\n     */\n    function _revertIfNotApprovedValidator(address validator_) internal view {\n        if (!isValidatorApproved(validator_)) revert NotApprovedValidator(validator_);\n    }\n\n    /**\n     * @dev   Reverts if minter position will be undercollateralized after changes.\n     * @param minter_          The address of the minter\n     * @param additionalOwedM_ The amount of additional owed M the action will add to minter's position\n     */\n    function _revertIfUndercollateralized(address minter_, uint240 additionalOwedM_) internal view {\n        uint256 maxAllowedActiveOwedM_ = maxAllowedActiveOwedMOf(minter_);\n\n        unchecked {\n            uint256 finalActiveOwedM_ = uint256(activeOwedMOf(minter_)) + additionalOwedM_;\n\n            if (finalActiveOwedM_ > maxAllowedActiveOwedM_) {\n                revert Undercollateralized(finalActiveOwedM_, maxAllowedActiveOwedM_);\n            }\n        }\n    }\n\n    /**\n     * @dev    Checks that enough valid unique signatures were provided.\n     * @param  minter_       The address of the minter.\n     * @param  collateral_   The amount of collateral.\n     * @param  retrievalIds_ The list of outstanding collateral retrieval IDs to resolve.\n     * @param  metadataHash_ The hash of metadata of the collateral update, reserved for future informational use.\n     * @param  validators_   The list of validators.\n     * @param  timestamps_   The list of validator timestamps for the collateral update signatures.\n     * @param  signatures_   The list of signatures.\n     * @return minTimestamp_ The minimum timestamp across all valid timestamps with valid signatures.\n     */\n    function _verifyValidatorSignatures(\n        address minter_,\n        uint256 collateral_,\n        uint256[] calldata retrievalIds_,\n        bytes32 metadataHash_,\n        address[] calldata validators_,\n        uint256[] calldata timestamps_,\n        bytes[] calldata signatures_\n    ) internal returns (uint40 minTimestamp_) {\n        minTimestamp_ = uint40(block.timestamp);\n\n        uint256 validCount_;\n\n        for (uint256 index_; index_ < signatures_.length; ++index_) {\n            unchecked {\n                // Check that validator address is unique and not accounted for\n                // NOTE: We revert here because this failure is entirely within the minter's control.\n                if (index_ > 0 && validators_[index_] <= validators_[index_ - 1]) revert InvalidSignatureOrder();\n            }\n\n            if (\n                !_verifyValidatorSignature(\n                    minter_,\n                    collateral_,\n                    retrievalIds_,\n                    metadataHash_,\n                    validators_[index_],\n                    timestamps_[index_],\n                    signatures_[index_]\n                )\n            ) continue;\n\n            // Find minimum between all valid timestamps for valid signatures.\n            minTimestamp_ = UIntMath.min40(minTimestamp_, uint40(timestamps_[index_]));\n\n            unchecked {\n                ++validCount_;\n            }\n        }\n\n        uint256 requiredThreshold_ = updateCollateralValidatorThreshold();\n\n        if (validCount_ < requiredThreshold_) revert NotEnoughValidSignatures(validCount_, requiredThreshold_);\n    }\n\n    /**\n     * @dev    Checks that a signature is a valid validator signature.\n     * @param  minter_       The address of the minter.\n     * @param  collateral_   The amount of collateral.\n     * @param  retrievalIds_ The list of outstanding collateral retrieval IDs to resolve.\n     * @param  metadataHash_ The hash of metadata of the collateral update, reserved for future informational use.\n     * @param  validator_    The address of a validator.\n     * @param  timestamp_    The timestamp for the collateral update signature.\n     * @param  signature_    The signature from the validator.\n     * @return Whether the signature is a valid validator signature or not.\n     */\n    function _verifyValidatorSignature(\n        address minter_,\n        uint256 collateral_,\n        uint256[] calldata retrievalIds_,\n        bytes32 metadataHash_,\n        address validator_,\n        uint256 timestamp_,\n        bytes calldata signature_\n    ) internal returns (bool) {\n        // Check that the timestamp is not 0.\n        // NOTE: Revert here because this failure is entirely within the minter's control.\n        if (timestamp_ == 0) revert ZeroTimestamp();\n\n        // Check that the timestamp is not in the future.\n        // NOTE: Revert here because this failure is entirely within the minter's control.\n        if (timestamp_ > uint40(block.timestamp)) revert FutureTimestamp();\n\n        uint256 lastTimestamp_ = _lastSignatureTimestamp[minter_][validator_];\n\n        // Check that the timestamp is not older than the last signature timestamp.\n        // NOTE: Revert here because this failure is entirely within the minter's control.\n        if (timestamp_ <= lastTimestamp_) revert OutdatedValidatorTimestamp(validator_, timestamp_, lastTimestamp_);\n\n        // Check that validator is approved by TTG.\n        if (!isValidatorApproved(validator_)) return false;\n\n        // Check that ECDSA or ERC1271 signatures for given digest are valid.\n        if (\n            !SignatureChecker.isValidSignature(\n                validator_,\n                _getUpdateCollateralDigest(minter_, collateral_, retrievalIds_, metadataHash_, timestamp_),\n                signature_\n            )\n        ) return false;\n\n        // Save the last signature timestamp for the minter and validator combination.\n        _lastSignatureTimestamp[minter_][validator_] = timestamp_;\n\n        return true;\n    }\n}\n","deployed_bytecode":"0x608060405234801561000f575f80fd5b506004361061037d575f3560e01c8063a1088459116101d4578063c8a7d5bf11610109578063e62aa759116100a9578063f20eb87d11610079578063f20eb87d14610b48578063f5abed3214610b5b578063f7a31df614610b6e578063f962a44b14610b81575f80fd5b8063e62aa75914610a96578063e806250a14610ad3578063eda1599a14610b22578063f00c280c14610b35575f80fd5b8063d4084620116100e4578063d408462014610971578063d69527111461097a578063d6b7494f14610994578063e1ebf1ad1461099c575f80fd5b8063c8a7d5bf146108f8578063c8da88e11461093d578063cbf062f714610950575f80fd5b8063aab1d86f11610174578063b9f412b01161014f578063b9f412b01461085b578063c107634c14610863578063c2ee3a08146108b5578063c3b6f939146108d1575f80fd5b8063aab1d86f1461082d578063af9979c914610840578063b599105c14610853575f80fd5b8063a49c8461116101af578063a49c846114610773578063a59b9a35146107bb578063a6ce63cd146107ce578063a8c01961146107f5575f80fd5b8063a108845914610750578063a178094414610758578063a29b67ce1461076b575f80fd5b80634be1c1cd116102b557806374aaf5e91161025557806384b0196e1161022557806384b0196e146106d95780638fb7faf2146106f45780639675adb0146106fc57806399799bbd14610748575f80fd5b806374aaf5e9146106275780637572840e1461063a5780637ad636761461064d5780637efb685b1461069a575f80fd5b8063578f2aa011610290578063578f2aa0146105a7578063663485d7146105c25780636850a999146105cb57806371f8ffe5146105fd575f80fd5b80634be1c1cd146105595780635130406b1461056c57806353d96f2c1461057f575f80fd5b80633644e51511610320578063433ae061116102fb578063433ae061146104ee57806343dc2cad14610517578063452b9fd81461052a57806346f97d0b14610532575f80fd5b80633644e515146104ad5780633b547ae5146104c35780633f9bcc6c146104e6575f80fd5b806314bc32e81161035b57806314bc32e8146104105780631aefb1071461043a57806326987b601461047c57806334636e8e146104a5575f80fd5b80630ab18476146103815780630b88f09c146103a35780630ec06104146103b8575b5f80fd5b610389610b89565b60405163ffffffff90911681526020015b60405180910390f35b6103b66103b1366004614b16565b610bc0565b005b6103cb6103c6366004614b3e565b610ced565b604080516dffffffffffffffffffffffffffff90931683527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911660208301520161039a565b61042361041e366004614b6e565b610fb3565b60405165ffffffffffff909116815260200161039a565b61044d610448366004614b98565b611222565b6040517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116815260200161039a565b6104846112af565b6040516fffffffffffffffffffffffffffffffff909116815260200161039a565b61038961133b565b6104b5611368565b60405190815260200161039a565b6104d66104d1366004614b98565b6113bd565b604051901515815260200161039a565b6103896113ee565b6105016104fc366004614bf2565b611426565b60405164ffffffffff909116815260200161039a565b6103b6610525366004614b98565b61154b565b61038961165e565b6104b57f22b57ca54bd15c6234b29e87aa1d76a0841b6e65e63d7acacef989de0bc3ff9e81565b61044d610567366004614b98565b61168b565b6104b561057a366004614cc2565b61170b565b5f546105019074010000000000000000000000000000000000000000900464ffffffffff1681565b5f54610484906fffffffffffffffffffffffffffffffff1681565b610389610e1081565b6105de6105d9366004614b98565b611725565b6040516dffffffffffffffffffffffffffff909116815260200161039a565b60025461044d907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1681565b6104b5610635366004614b98565b61179f565b610501610648366004614b98565b611820565b61050161065b366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f908152600460205260409020600201546a0100000000000000000000900464ffffffffff1690565b6105016106a8366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f9081526004602052604090206002015464ffffffffff1690565b6106e161186b565b60405161039a9796959493929190614d94565b61044d6119a4565b6107237f000000000000000000000000d7298f620b0f752cf41bd818a16c756d9dcaa34f81565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161039a565b61044d6119c2565b610723611aff565b610501610766366004614b98565b611b29565b610389611b9b565b610501610781366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f9081526004602052604090206002015465010000000000900464ffffffffff1690565b6103cb6107c9366004614e54565b611bd3565b6107237f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c81565b6104d6610803366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f9081526004602052604090205460ff1690565b61044d61083b366004614b98565b61202d565b61044d61084e366004614b98565b6122a1565b6104b561231e565b610484612348565b610501610871366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f908152600460205260409020600201546f01000000000000000000000000000000900464ffffffffff1690565b6108be61271081565b60405161ffff909116815260200161039a565b6107237f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b81565b6104b5610906366004614e6b565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815260086020908152604080832093909416825291909152205490565b61042361094b366004614e54565b6124f5565b5f54700100000000000000000000000000000000900463ffffffff16610389565b61038961fde881565b6003546105de906dffffffffffffffffffffffffffff1681565b6103896127ea565b610a2c6109aa366004614b98565b73ffffffffffffffffffffffffffffffffffffffff9081165f908152600560205260409020805460019091015465ffffffffffff82169364ffffffffff6601000000000000840416936b010000000000000000000000909304909216917dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911690565b6040805165ffffffffffff909516855264ffffffffff909316602085015273ffffffffffffffffffffffffffffffffffffffff909116918301919091527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16606082015260800161039a565b6104d6610aa4366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f90815260046020526040902054610100900460ff1690565b6104d6610ae1366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f908152600460205260409020600201546a0100000000000000000000900464ffffffffff16421090565b61044d610b30366004614b16565b612817565b6103cb610b43366004614b16565b6128bc565b610501610b56366004614b98565b6128f4565b61044d610b69366004614b98565b6129b8565b6104d6610b7c366004614b98565b612a36565b61044d612a61565b5f610bbb610bb67f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c612a94565b612abf565b905090565b610bc933612ace565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526005602052604090205465ffffffffffff168181141580610c0b575065ffffffffffff8116155b15610c42576040517fd148789900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f8181526005602052604080822080547fff0000000000000000000000000000000000000000000000000000000000000016815560010180547fffff0000000000000000000000000000000000000000000000000000000000001690555133929165ffffffffffff8516917f84fab121b74a9cdfebabf1215a1abbe5fe44ba6c1920780c593aa5102a4062369190a4505050565b5f80831580610cfa575082155b15610d31576040517f97b9d4c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85165f908152600460205260409020805460ff1680158015610d6f57508154610100900460ff16155b15610da6576040517f7bcd1d8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015610e5d57610db587612b28565b610dd087610dc288612cb7565b610dcb88612d04565b612d5d565b604080516dffffffffffffffffffffffffffff841681527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83166020820152929650909450339173ffffffffffffffffffffffffffffffffffffffff8a16917f48f6e7b6e5f16208a0eab9aa837aca65cc7ec94c304ed11ed98c2efc418ba50e910160405180910390a3610ee0565b610e6f87610e6a87612d04565b612ee5565b6040517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82168152909350339073ffffffffffffffffffffffffffffffffffffffff8916907f1391bf1af04eb2e8c6bd62f9c85f621584bc4ed7d2a6def75a0a0835756415429060200160405180910390a35b6040517f9dc29fac0000000000000000000000000000000000000000000000000000000081523360048201527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660248201527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b73ffffffffffffffffffffffffffffffffffffffff1690639dc29fac906044015f604051808303815f87803b158015610f8a575f80fd5b505af1158015610f9c573d5f803e3d5ffd5b50505050610fa8612348565b505050935093915050565b5f33610fbe81612f8c565b610fc733612fea565b835f03611000576040517f215b990c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831661104d576040517f785187dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61105785612d04565b90506110633382613060565b600380547fffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffff81166e0100000000000000000000000000009182900465ffffffffffff908116600190810180831694850293909317909455604080516080810182528481524264ffffffffff908116602080840191825273ffffffffffffffffffffffffffffffffffffffff8d81168587018181527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d811660608901818152335f818152600589528c90209a518b54995195519d167fffffffffffffffffffffffffffffffffffffffffff00000000000000000000009099169890981766010000000000009490991693909302979097177fff0000000000000000000000000000000000000000ffffffffffffffffffffff166b0100000000000000000000009a9094169990990292909217865590519490990180547fffff00000000000000000000000000000000000000000000000000000000000016949096169390931790945591519182529297509092917fc9b63ed98dd6e3f2536b8c9cd1668dd153c8a9207579556cb74ce9168b9c21d8910160405180910390a4505092915050565b5f61122c82611820565b64ffffffffff16421061124057505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600460205260409020600181015481547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9182169162010000909104168082106112a757505f949350505050565b039392505050565b5f8054610bbb90611322906fffffffffffffffffffffffffffffffff81169061131d906112f590700100000000000000000000000000000000900463ffffffff16613104565b5f5474010000000000000000000000000000000000000000900464ffffffffff16420361311b565b61313d565b71ffffffffffffffffffffffffffffffffffff16613171565b5f610bbb610bb67f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c61318c565b5f7f0000000000000000000000000000000000000000000000000000000000000001461461139857610bbb6131b7565b507fd97585e0f367b08779b6f85292c92c33e8b97a9e76ece7ba55e300315d51112d90565b5f6113e87f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c83613252565b92915050565b5f610bbb61fde8611421610bb67f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c61327e565b6132a9565b5f3361143181612f8c565b86831415806114405750828514155b15611477576040517fa68dc7d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61148a338d8d8d8d8d8d8d8d8d8d6132ca565b915061149533612b28565b61149f33836134a1565b5f6114a98d612d04565b90505f6114b7338e8e6136bd565b604080517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85811682528316602082015264ffffffffff87168183015290519192508c9133917f8c7a373ea6d1cedfcb77f0e5520921cc5d5a1a16b960c0c13c0f96b8dc24caa8919081900360600190a3611531338386613868565b611539612348565b505050509a9950505050505050505050565b61155481612a36565b61158a576040517f70b34fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090208054610100900460ff16156115ef576040517f30b2dfb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178155604051339073ffffffffffffffffffffffffffffffffffffffff8416907f2531adeb71f8681e6f4644f88cb102c71370151986071c92d43a7e82d217462a905f90a35050565b5f610bbb610bb67f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c6139aa565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff166116bd575f6113e8565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660205260409020546113e8907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166139d5565b5f61171a8787878787876139e7565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff16611757575f6113e8565b5073ffffffffffffffffffffffffffffffffffffffff165f908152600660205260409020547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff166117d1575f6113e8565b6127106117dc6113ee565b63ffffffff166117eb84611222565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16028161181957611819614e93565b0492915050565b5f611829611b9b565b73ffffffffffffffffffffffffffffffffffffffff9092165f9081526004602052604090206002015464ffffffffff1663ffffffff9290921691909101919050565b5f606080828080836001463084806040519080825280602002602001820160405280156118a2578160200160208202803683370190505b507f0f0000000000000000000000000000000000000000000000000000000000000094939291908480546118d590614ec0565b80601f016020809104026020016040519081016040528092919081815260200182805461190190614ec0565b801561194c5780601f106119235761010080835404028352916020019161194c565b820191905f5260205f20905b81548152906001019060200180831161192f57829003601f168201915b505050505094506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525093929190965096509650965096509650965090919293949596565b6003545f90610bbb906dffffffffffffffffffffffffffff166139d5565b5f807f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b73ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a2d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a519190614f11565b6002546003549192505f917dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911690611aa0906dffffffffffffffffffffffffffff16611a9b6112af565b613ab8565b611aaa9190614f55565b9050817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161115611afa5703919050565b505090565b5f610bbb7f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c613ac3565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260046020526040812081611b56611b9b565b60028301549091505f90611b7e9064ffffffffff808216916501000000000090041684613af4565b9150611b92905063ffffffff831682614f93565b95945050505050565b5f610bbb611bcb610bb67f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c613b7d565b610e10613ba8565b5f8033611bdf81612f8c565b611be833612fea565b335f908152600560205260409020805460018201547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16935065ffffffffffff81169064ffffffffff6601000000000000820416906b010000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16878314611c99576040517fd148789900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611ca261133b565b63ffffffff16830190508064ffffffffff16421015611cfb576040517fdddc549900000000000000000000000000000000000000000000000000000000815264ffffffffff821660048201526024015b60405180910390fd5b5f611d04610b89565b63ffffffff16820190508064ffffffffff16421115611d58576040517fa170e12000000000000000000000000000000000000000000000000000000000815264ffffffffff82166004820152602401611cf2565b5050611d643387613060565b335f90815260056020526040902080547fff0000000000000000000000000000000000000000000000000000000000000016815560010180547fffff000000000000000000000000000000000000000000000000000000000000169055611dca86613bc2565b600354604080516dffffffffffffffffffffffffffff80851682527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b166020830152939a509290911691339165ffffffffffff8716917fc7f1a91b0a382c263a18fea7b2908a6fcd90ebf2a9fde4bdf483b8ecceff1311910160405180910390a36002546dffffffffffffffffffffffffffff828116818b160191611e8d907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16613bc2565b6dffffffffffffffffffffffffffff16820110611ed6576040517f1123990900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff928316179055335f908152600660205260409081902080547fffff0000000000000000000000000000000000000000000000000000000000008116938c167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918216018116939093179055517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015291891660248201527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b91909116906340c10f19906044015f604051808303815f87803b158015612003575f80fd5b505af1158015612015573d5f803e3d5ffd5b50505050612021612348565b50505050505050915091565b5f8161203881612f8c565b61204183612a36565b15612078576040517fe2a4b46500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61208183612b28565b5f61208b84611725565b9050612096816139d5565b600380547fffffffffffffffffffffffffffffffffffff000000000000000000000000000081166dffffffffffffffffffffffffffff918216859003909116179055600280547fffff00000000000000000000000000000000000000000000000000000000000081167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91821684018216179091556040519082168152909350339073ffffffffffffffffffffffffffffffffffffffff8616907f441d4e9d05bbbeb9019e911d76bdd0bf9389b0755175567d4e59607be5348d9b9060200160405180910390a373ffffffffffffffffffffffffffffffffffffffff84165f908152600460209081526040808320838155600180820180547fffff0000000000000000000000000000000000000000000000000000000000009081169091556002830180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556005855283862080547fff0000000000000000000000000000000000000000000000000000000000000016815590910180548216905581547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017909155600690925290912080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86169216919091179055612299612348565b505050919050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff166123175773ffffffffffffffffffffffffffffffffffffffff82165f908152600660205260409020547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166113e8565b5f92915050565b5f610bbb7f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c613bd4565b5f806123526119c2565b90507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81161561245d576040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d7298f620b0f752cf41bd818a16c756d9dcaa34f811660048301527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660248301527f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b16906340c10f19906044015f604051808303815f87803b158015612446575f80fd5b505af1158015612458573d5f803e3d5ffd5b505050505b612465613bff565b91507f000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b73ffffffffffffffffffffffffffffffffffffffff1663b9f412b06040518163ffffffff1660e01b81526004016020604051808303815f875af11580156124d1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611afa9190614fb1565b5f3361250081612f8c565b825f03612539576040517faa58a19400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff8116740100000000000000000000000000000000000000009182900465ffffffffffff90811660010190811690920217909155335f9081526004602052604081208054929450916201000090047dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16906125d586612d04565b60018401549091505f9061260a9083907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16614f55565b9050807dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1610156126b0576040517f10bb3f430000000000000000000000000000000000000000000000000000000081527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808316600483015284166024820152604401611cf2565b60028401805464ffffffffff42166f01000000000000000000000000000000027fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff9091161790556001840180547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8084167fffff00000000000000000000000000000000000000000000000000000000000092831617909255335f81815260076020908152604080832065ffffffffffff8d16845290915281208054948716949093169390931790915561278191613060565b6040517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168152339065ffffffffffff8816907f83f709bc37ea6de507e30b18311aa7a86c08833fa447f2c76ccc463c8936c4999060200160405180910390a35050505050919050565b5f610bbb610bb67f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c613d4f565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260046020526040812054610100900460ff166128b35773ffffffffffffffffffffffffffffffffffffffff83165f9081526007602052604081209061287684613d7a565b65ffffffffffff16815260208101919091526040015f20547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166128b5565b5f5b9392505050565b5f806128e9846128d36128ce86612d04565b613dbb565b6dffffffffffffffffffffffffffff1685610ced565b909590945092505050565b5f6128fe33612ace565b61290661165e565b73ffffffffffffffffffffffffffffffffffffffff83165f8181526004602090815260409182902060020180547fffffffffffffffffffffffffffffffffff0000000000ffffffffffffffffffff166a010000000000000000000063ffffffff96909616420164ffffffffff811696870291909117909155915193845290935090917f1ac7b35bca40be2823e4880f1b2e9ef02fa4c7bd62aed73c2ea2959232a1f9f5910160405180910390a2919050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260046020526040812054610100900460ff166123175773ffffffffffffffffffffffffffffffffffffffff82165f908152600460205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166113e8565b5f6113e87f000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c83613dcd565b6002545f907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16612a8e6119a4565b01905090565b5f6113e8827f6d696e745f74746c000000000000000000000000000000000000000000000000613df9565b5f6113e88263ffffffff613e88565b612ad7816113bd565b612b25576040517ff731555300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611cf2565b50565b5f612b3282611725565b9050806dffffffffffffffffffffffffffff165f03612b4f575050565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260046020526040812060028101549091908190612ba29064ffffffffff8082169165010000000000900416612b9d611b9b565b613af4565b915091508164ffffffffff165f03612bbb575050505050565b808360020160056101000a81548164ffffffffff021916908364ffffffffff1602179055505f612c0d868464ffffffffff16876dffffffffffffffffffffffffffff16612c089190614fe0565b613e96565b9050806dffffffffffffffffffffffffffff165f03612c2e57505050505050565b8573ffffffffffffffffffffffffffffffffffffffff167f4fb8bb7b0278c9f68d34ce501b521ecd2e3c1bc48fe37eda47db36da6defc7ef84612c70846139d5565b6040805164ffffffffff90931683527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911660208301520160405180910390a2505050505050565b5f6dffffffffffffffffffffffffffff821115612d00576040517fca21dbd100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b5f7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612d00576040517f2a49c10d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80612d71612d6b86611725565b85613ff6565b9150612d7c826139d5565b9050827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161115612e22576040517f37666f1d0000000000000000000000000000000000000000000000000000000081527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808316600483015284166024820152604401611cf2565b73ffffffffffffffffffffffffffffffffffffffff949094165f90815260066020526040902080547fffff00000000000000000000000000000000000000000000000000000000000081166dffffffffffffffffffffffffffff8481167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9384160390921617909155600380547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000811690831684900390921691909117905593915050565b5f612ef8612ef2846122a1565b83614024565b73ffffffffffffffffffffffffffffffffffffffff9093165f90815260066020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80821686900381167fffff0000000000000000000000000000000000000000000000000000000000009283161790925560028054808416879003909316929091169190911790555090919050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16612b25576040517f7bcd1d8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600460205260409020600201546a0100000000000000000000900464ffffffffff16421015612b25576040517f1526e62e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61306a8361179f565b90505f827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166130978561168b565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16019050818111156130fe576040517f5033ec120000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401611cf2565b50505050565b5f61271063ffffffff831664e8d4a5100002611819565b5f6128b56301e1338067ffffffffffffffff851663ffffffff85160204614072565b5f64e8d4a510006fffffffffffffffffffffffffffffffff841665ffffffffffff84160264e8d4a50fff015b049392505050565b5f6113e8826fffffffffffffffffffffffffffffffff613e88565b5f6113e8827f6d696e745f64656c617900000000000000000000000000000000000000000000613df9565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f1b60016040516131ea919061501e565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f6128b5837f76616c696461746f727300000000000000000000000000000000000000000000846140eb565b5f6113e8827f6d696e745f726174696f00000000000000000000000000000000000000000000613df9565b5f8163ffffffff168363ffffffff16106132c357816128b5565b5090919050565b425f805b83811015613440575f8111801561336057508888600183038181106132f5576132f56150f3565b905060200201602081019061330a9190614b98565b73ffffffffffffffffffffffffffffffffffffffff16898983818110613332576133326150f3565b90506020020160208101906133479190614b98565b73ffffffffffffffffffffffffffffffffffffffff1611155b15613397576040517f139f3c9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134088e8e8e8e8e8e8e888181106133b1576133b16150f3565b90506020020160208101906133c69190614b98565b8d8d898181106133d8576133d86150f3565b905060200201358c8c8a8181106133f1576133f16150f3565b90506020028101906134039190615120565b61418b565b156134385761342f83888884818110613423576134236150f3565b9050602002013561434d565b92508160010191505b6001016132ce565b505f61344a61231e565b905080821015613490576040517f74e8306f0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401611cf2565b50509b9a5050505050505050505050565b5f6134ab83611725565b9050806dffffffffffffffffffffffffffff165f036134c957505050565b5f6134d38461179f565b90507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106135005750505050565b5f61350a82613dbb565b9050826dffffffffffffffffffffffffffff16816dffffffffffffffffffffffffffff161061353a575050505050565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260046020526040812060028101549091906135839064ffffffffff8082169165010000000000900416614369565b90508064ffffffffff168664ffffffffff16116135a35750505050505050565b8086038386035f6135f98a6135b6611b9b565b63ffffffff168564ffffffffff1685026dffffffffffffffffffffffffffff16816135e3576135e3614e93565b046dffffffffffffffffffffffffffff16613e96565b9050806dffffffffffffffffffffffffffff165f0361361e5750505050505050505050565b8973ffffffffffffffffffffffffffffffffffffffff167fadbe0a005ef4d2903a69fd3053b1c8dfc083430632f549a92a1d3bc648104ae361365f846139d5565b85613669856139d5565b604080517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff948516815264ffffffffff93909316602084015292168183015290519081900360600190a250505050505050505050565b5f805b828110156137e9575f6136ea8585848181106136de576136de6150f3565b90506020020135613d7a565b73ffffffffffffffffffffffffffffffffffffffff87165f90815260076020908152604080832065ffffffffffff851684529091528120549192507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116908190036137565750506137e1565b73ffffffffffffffffffffffffffffffffffffffff87165f81815260076020908152604080832065ffffffffffff8716808552925280832080547fffff000000000000000000000000000000000000000000000000000000000000169055519684019690917f7318b8ec2c2570ee6068ac690bbda62f9d13d38d52e36e23e0885101a5ffab0791a350505b6001016136c0565b5073ffffffffffffffffffffffffffffffffffffffff9093165f90815260046020526040902060010180547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808216869003167fffff0000000000000000000000000000000000000000000000000000000000009091161790555090919050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260046020526040812060028101549091906138dd906138bf9064ffffffffff808216916f01000000000000000000000000000000900416614369565b6138d66138ca611b9b565b63ffffffff164261434d565b4203614369565b90508064ffffffffff168364ffffffffff1611613937576040517f17ea884500000000000000000000000000000000000000000000000000000000815264ffffffffff808516600483015282166024820152604401611cf2565b5080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909316620100000261ffff9093169290921782556002909101805464ffffffffff9092167fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117905550565b5f6113e8827f6d696e7465725f667265657a655f74696d650000000000000000000000000000613df9565b5f6113e8826139e26112af565b614385565b5f61171a7f22b57ca54bd15c6234b29e87aa1d76a0841b6e65e63d7acacef989de0bc3ff9e5f1b88888888604051602001613a23929190615181565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083019590955273ffffffffffffffffffffffffffffffffffffffff909316928101929092526060820152608081019190915260a0810185905260c0810184905260e00160405160208183030381529060405280519060200120614390565b5f6128b583836143f1565b5f6113e8613af1837f6d696e7465725f726174655f6d6f64656c000000000000000000000000000000613df9565b90565b5f805f613b018686614369565b90508564ffffffffff165f03613b1b575f92509050613b75565b5f613b2682426151c1565b90508463ffffffff168164ffffffffff161015613b4857505f92509050613b75565b8463ffffffff168164ffffffffff1681613b6457613b64614e93565b0493505063ffffffff841683020190505b935093915050565b5f6113e8827f7570646174655f636f6c6c61746572616c5f696e74657276616c000000000000613df9565b5f8163ffffffff168363ffffffff16116132c357816128b5565b5f6113e882613bcf6112af565b614422565b5f6113e8827f7570646174655f636f6c6c61746572616c5f7468726573686f6c640000000000613df9565b5f80613c0961442d565b5f5490915064ffffffffff740100000000000000000000000000000000000000009091041642148015613c5957505f5463ffffffff82811670010000000000000000000000000000000090920416145b15613c775750505f546fffffffffffffffffffffffffffffffff1690565b613c7f6112af565b5f80546fffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811770010000000000000000000000000000000063ffffffff8616908102919091177fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000004264ffffffffff16021783556040519395509290917f8f9a1730052b867fdeb484b52fbc51e9bb62830781805ac95c382bbf8ea717a291a35090565b5f6113e8827f70656e616c74795f726174650000000000000000000000000000000000000000613df9565b5f65ffffffffffff821115612d00576040517f069c6d4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6113e882613dc86112af565b61452d565b5f6128b5837f6d696e7465727300000000000000000000000000000000000000000000000000846140eb565b6040517f8eaa6ac0000000000000000000000000000000000000000000000000000000008152600481018290525f9073ffffffffffffffffffffffffffffffffffffffff841690638eaa6ac090602401602060405180830381865afa158015613e64573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128b59190614f11565b5f8183106132c357816128b5565b5f8172ffffffffffffffffffffffffffffffffffffff165f03613eba57505f6113e8565b5f613ec36127ea565b90508063ffffffff165f03613edb575f9150506113e8565b60035461271063ffffffff831672ffffffffffffffffffffffffffffffffffffff86160204906dffffffffffffffffffffffffffff908116820190811115613f3a5750506003546dffffffffffffffffffffffffffff90811681038116905b600380547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff92831617905573ffffffffffffffffffffffffffffffffffffffff959095165f90815260066020526040902080547fffff00000000000000000000000000000000000000000000000000000000000081169683167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918216011695909517909455509192915050565b5f816dffffffffffffffffffffffffffff16836dffffffffffffffffffffffffffff16106132c357816128b5565b5f817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16106132c357816128b5565b5f68ffffffffffffffffff821680026123288102642e90edd000820464174876e800830402016c010f6b2be4706a13fc200000000182633b9aca008304669536c708910000018568ffffffffffffffffff1602905080820381830164e8d4a5100002816140e1576140e1614e93565b0495945050505050565b6040517fd7d1c1c00000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82811660248301525f919085169063d7d1c1c090604401602060405180830381865afa15801561415f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061418391906151df565b949350505050565b5f835f036141c5576040517fda16d76700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4264ffffffffff16841115614206576040517f0ff02cef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808b165f90815260086020908152604080832093891683529290522054808511614297576040517f2e7a0bcb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871660048201526024810186905260448101829052606401611cf2565b6142a0866113bd565b6142ad575f915050614340565b6142fa866142bf8d8d8d8d8d8c6139e7565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061453892505050565b614307575f915050614340565b505073ffffffffffffffffffffffffffffffffffffffff808a165f90815260086020908152604080832093881683529290522083905560015b9998505050505050505050565b5f8164ffffffffff168364ffffffffff16106132c357816128b5565b5f8164ffffffffff168364ffffffffff16116132c357816128b5565b5f6128b58383614555565b5f614399611368565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b5f64e8d4a510006dffffffffffffffffffffffffffff84166fffffffffffffffffffffffffffffffff841602613169565b5f6128b5838361458d565b5f805f614438611aff565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2c4e722e00000000000000000000000000000000000000000000000000000000179052905173ffffffffffffffffffffffffffffffffffffffff92909216916144b491906151fe565b5f60405180830381855afa9150503d805f81146144ec576040519150601f19603f3d011682016040523d82523d5f602084013e6144f1565b606091505b509150915081801561450557506020815110155b61450f575f614526565b61452681806020019051810190610bb69190614f11565b9250505090565b5f6128b5838361464e565b5f6145448484846146e5565b806141835750614183848484614734565b5f64e8d4a510006dffffffffffffffffffffffffffff84166fffffffffffffffffffffffffffffffff84160264e8d4a50fff01613169565b5f816fffffffffffffffffffffffffffffffff165f036145d9576040517f23d359a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128b56fffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861664e8d4a51000028201018161464857614648614e93565b04612cb7565b5f816fffffffffffffffffffffffffffffffff165f0361469a576040517f23d359a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128b56fffffffffffffffffffffffffffffffff83167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff851664e8d4a51000028161464857614648614e93565b5f815160400361470e57602082015160408301516147058686848461487d565b925050506128b5565b5f61471a8585856148a6565b600581111561472b5761472b615219565b14949350505050565b5f805f8573ffffffffffffffffffffffffffffffffffffffff168585604051602401614761929190615246565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1626ba7e00000000000000000000000000000000000000000000000000000000179052516147e291906151fe565b5f60405180830381855afa9150503d805f811461481a576040519150601f19603f3d011682016040523d82523d5f602084013e61481f565b606091505b509150915081801561483357506020815110155b8015614873575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906148719083016020908101908401614f11565b145b9695505050505050565b5f8061488b868686866148e0565b600581111561489c5761489c615219565b1495945050505050565b5f805f6148b3858561491b565b90925090505f8260058111156148cb576148cb615219565b146148d65781614873565b614873868261495f565b5f805f6148ee86868661499a565b90925090505f82600581111561490657614906615219565b14614911578161171a565b61171a878261495f565b5f8082516041146149315750600290505f614958565b6020830151604084015160608501515f1a9190614950878484846149e1565b945094505050505b9250929050565b5f8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146128b35760056128b5565b5f80601b60ff84901c017f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84166149d3878388846149e1565b935093505050935093915050565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614a165750600390505f614ae5565b8460ff16601b14158015614a2e57508460ff16601c14155b15614a3e5750600490505f614ae5565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614a8e573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615614adc575f81614ae0565b60015f5b915091505b94509492505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b11575f80fd5b919050565b5f8060408385031215614b27575f80fd5b614b3083614aee565b946020939093013593505050565b5f805f60608486031215614b50575f80fd5b614b5984614aee565b95602085013595506040909401359392505050565b5f8060408385031215614b7f575f80fd5b82359150614b8f60208401614aee565b90509250929050565b5f60208284031215614ba8575f80fd5b6128b582614aee565b5f8083601f840112614bc1575f80fd5b50813567ffffffffffffffff811115614bd8575f80fd5b6020830191508360208260051b8501011115614958575f80fd5b5f805f805f805f805f8060c08b8d031215614c0b575f80fd5b8a35995060208b013567ffffffffffffffff80821115614c29575f80fd5b614c358e838f01614bb1565b909b50995060408d0135985060608d0135915080821115614c54575f80fd5b614c608e838f01614bb1565b909850965060808d0135915080821115614c78575f80fd5b614c848e838f01614bb1565b909650945060a08d0135915080821115614c9c575f80fd5b50614ca98d828e01614bb1565b915080935050809150509295989b9194979a5092959850565b5f805f805f8060a08789031215614cd7575f80fd5b614ce087614aee565b955060208701359450604087013567ffffffffffffffff811115614d02575f80fd5b614d0e89828a01614bb1565b979a9699509760608101359660809091013595509350505050565b5f5b83811015614d43578181015183820152602001614d2b565b50505f910152565b5f8151808452614d62816020860160208601614d29565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7fff00000000000000000000000000000000000000000000000000000000000000881681525f602060e06020840152614dd060e084018a614d4b565b8381036040850152614de2818a614d4b565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825260208088019350909101905f5b81811015614e4257835183529284019291840191600101614e26565b50909c9b505050505050505050505050565b5f60208284031215614e64575f80fd5b5035919050565b5f8060408385031215614e7c575f80fd5b614e8583614aee565b9150614b8f60208401614aee565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b600181811c90821680614ed457607f821691505b602082108103614f0b577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b5f60208284031215614f21575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff818116838216019080821115614f8c57614f8c614f28565b5092915050565b64ffffffffff818116838216019080821115614f8c57614f8c614f28565b5f60208284031215614fc1575f80fd5b81516fffffffffffffffffffffffffffffffff811681146128b5575f80fd5b72ffffffffffffffffffffffffffffffffffffff82811682821681810283169291811582850482141761501557615015614f28565b50505092915050565b5f8083545f60018260011c9150600183168061503b57607f831692505b60208084108203615073577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b81801561508757600181146150ba576150e5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528415158502890196506150e5565b5f8a8152602090205f5b868110156150dd5781548b8201529085019083016150c4565b505084890196505b509498975050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615153575f80fd5b83018035915067ffffffffffffffff82111561516d575f80fd5b602001915036819003821315614958575f80fd5b5f7f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156151ae575f80fd5b8260051b80858437919091019392505050565b64ffffffffff828116828216039080821115614f8c57614f8c614f28565b5f602082840312156151ef575f80fd5b815180151581146128b5575f80fd5b5f825161520f818460208701614d29565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f6141836040830184614d4b56fea2646970667358221220decb3a3a9db6ebea55049121aa2d482d98ca58a9ca23cfccb51d08010c78d75664736f6c63430008170033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"shanghai","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":999999},"remappings":[":common/=lib/protocol/lib/common/src/",":contract-test-utils/=lib/ttg/lib/erc20-helper/lib/contract-test-utils/contracts/",":ds-test/=lib/protocol/lib/solmate/lib/ds-test/src/",":erc20-helper/=lib/ttg/lib/erc20-helper/src/",":forge-std/=lib/forge-std/src/",":protocol/=lib/protocol/",":solmate/=lib/protocol/lib/solmate/src/",":ttg/=lib/ttg/"]},"optimization_runs":999999,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/full_match/1/0xf7f9638cb444D65e5A40bF5ff98ebE4ff319F04E/","decoded_constructor_args":[["0x119FbeeDD4F4f4298Fb59B720d5654442b81ae2c",{"internalType":"address","name":"ttgRegistrar_","type":"address"}],["0x866A2BF4E572CbcF37D5071A7a58503Bfb36be1b",{"internalType":"address","name":"mToken_","type":"address"}]],"compiler_version":"0.8.23+commit.f704f362","is_verified_via_verifier_alliance":false,"verified_at":"2024-05-16T12:01:36.674223Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x61012060405234801562000011575f80fd5b50604051620057f6380380620057f6833981016040819052620000349162000277565b60408051808201909152600d81526c4d696e7465724761746577617960981b60208201525f805464ffffffffff4216600160a01b027fffffffffffffff0000000000ffffffff000000000000000000000000000000009091161764e8d4a510001790556001620000a582826200034b565b5046608052620000b462000154565b60a052506001600160a01b03821660c0819052620000e55760405163b8eb034b60e01b815260040160405180910390fd5b5f620000f183620001f1565b6001600160a01b031660e0819052036200011e576040516331c1de8560e01b815260040160405180910390fd5b6001600160a01b0381166101008190526200014c5760405163b01d5e2b60e01b815260040160405180910390fd5b5050620004b4565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f1b600160405162000189919062000417565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f816001600160a01b031663fbfa77cf6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200022f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000255919062000491565b92915050565b80516001600160a01b038116811462000272575f80fd5b919050565b5f806040838503121562000289575f80fd5b62000294836200025b565b9150620002a4602084016200025b565b90509250929050565b634e487b7160e01b5f52604160045260245ffd5b600181811c90821680620002d657607f821691505b602082108103620002f557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200034657805f5260205f20601f840160051c81016020851015620003225750805b601f840160051c820191505b8181101562000343575f81556001016200032e565b50505b505050565b81516001600160401b03811115620003675762000367620002ad565b6200037f81620003788454620002c1565b84620002fb565b602080601f831160018114620003b5575f84156200039d5750858301515b5f19600386901b1c1916600185901b1785556200040f565b5f85815260208120601f198616915b82811015620003e557888601518255948401946001909101908401620003c4565b50858210156200040357878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f8083546200042681620002c1565b60018281168015620004415760018114620004575762000485565b60ff198416875282151583028701945062000485565b875f526020805f205f5b858110156200047c5781548a82015290840190820162000461565b50505082870194505b50929695505050505050565b5f60208284031215620004a2575f80fd5b620004ad826200025b565b9392505050565b60805160a05160c05160e05161010051615294620005625f395f81816108d601528181610f34015281816119c601528181611fbf01528181612405015261246901525f818161070101526123b701525f81816107d301528181610b9201528181611344015281816113c3015281816113fd0152818161166701528181611b0501528181611ba701528181612324015281816127f30152612a3c01525f61139b01525f61136b01526152945ff3fe608060405234801561000f575f80fd5b506004361061037d575f3560e01c8063a1088459116101d4578063c8a7d5bf11610109578063e62aa759116100a9578063f20eb87d11610079578063f20eb87d14610b48578063f5abed3214610b5b578063f7a31df614610b6e578063f962a44b14610b81575f80fd5b8063e62aa75914610a96578063e806250a14610ad3578063eda1599a14610b22578063f00c280c14610b35575f80fd5b8063d4084620116100e4578063d408462014610971578063d69527111461097a578063d6b7494f14610994578063e1ebf1ad1461099c575f80fd5b8063c8a7d5bf146108f8578063c8da88e11461093d578063cbf062f714610950575f80fd5b8063aab1d86f11610174578063b9f412b01161014f578063b9f412b01461085b578063c107634c14610863578063c2ee3a08146108b5578063c3b6f939146108d1575f80fd5b8063aab1d86f1461082d578063af9979c914610840578063b599105c14610853575f80fd5b8063a49c8461116101af578063a49c846114610773578063a59b9a35146107bb578063a6ce63cd146107ce578063a8c01961146107f5575f80fd5b8063a108845914610750578063a178094414610758578063a29b67ce1461076b575f80fd5b80634be1c1cd116102b557806374aaf5e91161025557806384b0196e1161022557806384b0196e146106d95780638fb7faf2146106f45780639675adb0146106fc57806399799bbd14610748575f80fd5b806374aaf5e9146106275780637572840e1461063a5780637ad636761461064d5780637efb685b1461069a575f80fd5b8063578f2aa011610290578063578f2aa0146105a7578063663485d7146105c25780636850a999146105cb57806371f8ffe5146105fd575f80fd5b80634be1c1cd146105595780635130406b1461056c57806353d96f2c1461057f575f80fd5b80633644e51511610320578063433ae061116102fb578063433ae061146104ee57806343dc2cad14610517578063452b9fd81461052a57806346f97d0b14610532575f80fd5b80633644e515146104ad5780633b547ae5146104c35780633f9bcc6c146104e6575f80fd5b806314bc32e81161035b57806314bc32e8146104105780631aefb1071461043a57806326987b601461047c57806334636e8e146104a5575f80fd5b80630ab18476146103815780630b88f09c146103a35780630ec06104146103b8575b5f80fd5b610389610b89565b60405163ffffffff90911681526020015b60405180910390f35b6103b66103b1366004614b16565b610bc0565b005b6103cb6103c6366004614b3e565b610ced565b604080516dffffffffffffffffffffffffffff90931683527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911660208301520161039a565b61042361041e366004614b6e565b610fb3565b60405165ffffffffffff909116815260200161039a565b61044d610448366004614b98565b611222565b6040517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116815260200161039a565b6104846112af565b6040516fffffffffffffffffffffffffffffffff909116815260200161039a565b61038961133b565b6104b5611368565b60405190815260200161039a565b6104d66104d1366004614b98565b6113bd565b604051901515815260200161039a565b6103896113ee565b6105016104fc366004614bf2565b611426565b60405164ffffffffff909116815260200161039a565b6103b6610525366004614b98565b61154b565b61038961165e565b6104b57f22b57ca54bd15c6234b29e87aa1d76a0841b6e65e63d7acacef989de0bc3ff9e81565b61044d610567366004614b98565b61168b565b6104b561057a366004614cc2565b61170b565b5f546105019074010000000000000000000000000000000000000000900464ffffffffff1681565b5f54610484906fffffffffffffffffffffffffffffffff1681565b610389610e1081565b6105de6105d9366004614b98565b611725565b6040516dffffffffffffffffffffffffffff909116815260200161039a565b60025461044d907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1681565b6104b5610635366004614b98565b61179f565b610501610648366004614b98565b611820565b61050161065b366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f908152600460205260409020600201546a0100000000000000000000900464ffffffffff1690565b6105016106a8366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f9081526004602052604090206002015464ffffffffff1690565b6106e161186b565b60405161039a9796959493929190614d94565b61044d6119a4565b6107237f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161039a565b61044d6119c2565b610723611aff565b610501610766366004614b98565b611b29565b610389611b9b565b610501610781366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f9081526004602052604090206002015465010000000000900464ffffffffff1690565b6103cb6107c9366004614e54565b611bd3565b6107237f000000000000000000000000000000000000000000000000000000000000000081565b6104d6610803366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f9081526004602052604090205460ff1690565b61044d61083b366004614b98565b61202d565b61044d61084e366004614b98565b6122a1565b6104b561231e565b610484612348565b610501610871366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f908152600460205260409020600201546f01000000000000000000000000000000900464ffffffffff1690565b6108be61271081565b60405161ffff909116815260200161039a565b6107237f000000000000000000000000000000000000000000000000000000000000000081565b6104b5610906366004614e6b565b73ffffffffffffffffffffffffffffffffffffffff9182165f90815260086020908152604080832093909416825291909152205490565b61042361094b366004614e54565b6124f5565b5f54700100000000000000000000000000000000900463ffffffff16610389565b61038961fde881565b6003546105de906dffffffffffffffffffffffffffff1681565b6103896127ea565b610a2c6109aa366004614b98565b73ffffffffffffffffffffffffffffffffffffffff9081165f908152600560205260409020805460019091015465ffffffffffff82169364ffffffffff6601000000000000840416936b010000000000000000000000909304909216917dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911690565b6040805165ffffffffffff909516855264ffffffffff909316602085015273ffffffffffffffffffffffffffffffffffffffff909116918301919091527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16606082015260800161039a565b6104d6610aa4366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f90815260046020526040902054610100900460ff1690565b6104d6610ae1366004614b98565b73ffffffffffffffffffffffffffffffffffffffff165f908152600460205260409020600201546a0100000000000000000000900464ffffffffff16421090565b61044d610b30366004614b16565b612817565b6103cb610b43366004614b16565b6128bc565b610501610b56366004614b98565b6128f4565b61044d610b69366004614b98565b6129b8565b6104d6610b7c366004614b98565b612a36565b61044d612a61565b5f610bbb610bb67f0000000000000000000000000000000000000000000000000000000000000000612a94565b612abf565b905090565b610bc933612ace565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526005602052604090205465ffffffffffff168181141580610c0b575065ffffffffffff8116155b15610c42576040517fd148789900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f8181526005602052604080822080547fff0000000000000000000000000000000000000000000000000000000000000016815560010180547fffff0000000000000000000000000000000000000000000000000000000000001690555133929165ffffffffffff8516917f84fab121b74a9cdfebabf1215a1abbe5fe44ba6c1920780c593aa5102a4062369190a4505050565b5f80831580610cfa575082155b15610d31576040517f97b9d4c400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff85165f908152600460205260409020805460ff1680158015610d6f57508154610100900460ff16155b15610da6576040517f7bcd1d8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015610e5d57610db587612b28565b610dd087610dc288612cb7565b610dcb88612d04565b612d5d565b604080516dffffffffffffffffffffffffffff841681527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83166020820152929650909450339173ffffffffffffffffffffffffffffffffffffffff8a16917f48f6e7b6e5f16208a0eab9aa837aca65cc7ec94c304ed11ed98c2efc418ba50e910160405180910390a3610ee0565b610e6f87610e6a87612d04565b612ee5565b6040517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82168152909350339073ffffffffffffffffffffffffffffffffffffffff8916907f1391bf1af04eb2e8c6bd62f9c85f621584bc4ed7d2a6def75a0a0835756415429060200160405180910390a35b6040517f9dc29fac0000000000000000000000000000000000000000000000000000000081523360048201527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690639dc29fac906044015f604051808303815f87803b158015610f8a575f80fd5b505af1158015610f9c573d5f803e3d5ffd5b50505050610fa8612348565b505050935093915050565b5f33610fbe81612f8c565b610fc733612fea565b835f03611000576040517f215b990c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff831661104d576040517f785187dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61105785612d04565b90506110633382613060565b600380547fffffffffffffffffffffffff000000000000ffffffffffffffffffffffffffff81166e0100000000000000000000000000009182900465ffffffffffff908116600190810180831694850293909317909455604080516080810182528481524264ffffffffff908116602080840191825273ffffffffffffffffffffffffffffffffffffffff8d81168587018181527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8d811660608901818152335f818152600589528c90209a518b54995195519d167fffffffffffffffffffffffffffffffffffffffffff00000000000000000000009099169890981766010000000000009490991693909302979097177fff0000000000000000000000000000000000000000ffffffffffffffffffffff166b0100000000000000000000009a9094169990990292909217865590519490990180547fffff00000000000000000000000000000000000000000000000000000000000016949096169390931790945591519182529297509092917fc9b63ed98dd6e3f2536b8c9cd1668dd153c8a9207579556cb74ce9168b9c21d8910160405180910390a4505092915050565b5f61122c82611820565b64ffffffffff16421061124057505f919050565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600460205260409020600181015481547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9182169162010000909104168082106112a757505f949350505050565b039392505050565b5f8054610bbb90611322906fffffffffffffffffffffffffffffffff81169061131d906112f590700100000000000000000000000000000000900463ffffffff16613104565b5f5474010000000000000000000000000000000000000000900464ffffffffff16420361311b565b61313d565b71ffffffffffffffffffffffffffffffffffff16613171565b5f610bbb610bb67f000000000000000000000000000000000000000000000000000000000000000061318c565b5f7f0000000000000000000000000000000000000000000000000000000000000000461461139857610bbb6131b7565b507f000000000000000000000000000000000000000000000000000000000000000090565b5f6113e87f000000000000000000000000000000000000000000000000000000000000000083613252565b92915050565b5f610bbb61fde8611421610bb67f000000000000000000000000000000000000000000000000000000000000000061327e565b6132a9565b5f3361143181612f8c565b86831415806114405750828514155b15611477576040517fa68dc7d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61148a338d8d8d8d8d8d8d8d8d8d6132ca565b915061149533612b28565b61149f33836134a1565b5f6114a98d612d04565b90505f6114b7338e8e6136bd565b604080517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85811682528316602082015264ffffffffff87168183015290519192508c9133917f8c7a373ea6d1cedfcb77f0e5520921cc5d5a1a16b960c0c13c0f96b8dc24caa8919081900360600190a3611531338386613868565b611539612348565b505050509a9950505050505050505050565b61155481612a36565b61158a576040517f70b34fc000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090208054610100900460ff16156115ef576040517f30b2dfb000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001178155604051339073ffffffffffffffffffffffffffffffffffffffff8416907f2531adeb71f8681e6f4644f88cb102c71370151986071c92d43a7e82d217462a905f90a35050565b5f610bbb610bb67f00000000000000000000000000000000000000000000000000000000000000006139aa565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff166116bd575f6113e8565b73ffffffffffffffffffffffffffffffffffffffff82165f908152600660205260409020546113e8907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166139d5565b5f61171a8787878787876139e7565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff16611757575f6113e8565b5073ffffffffffffffffffffffffffffffffffffffff165f908152600660205260409020547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff166117d1575f6113e8565b6127106117dc6113ee565b63ffffffff166117eb84611222565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16028161181957611819614e93565b0492915050565b5f611829611b9b565b73ffffffffffffffffffffffffffffffffffffffff9092165f9081526004602052604090206002015464ffffffffff1663ffffffff9290921691909101919050565b5f606080828080836001463084806040519080825280602002602001820160405280156118a2578160200160208202803683370190505b507f0f0000000000000000000000000000000000000000000000000000000000000094939291908480546118d590614ec0565b80601f016020809104026020016040519081016040528092919081815260200182805461190190614ec0565b801561194c5780601f106119235761010080835404028352916020019161194c565b820191905f5260205f20905b81548152906001019060200180831161192f57829003601f168201915b505050505094506040518060400160405280600181526020017f310000000000000000000000000000000000000000000000000000000000000081525093929190965096509650965096509650965090919293949596565b6003545f90610bbb906dffffffffffffffffffffffffffff166139d5565b5f807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a2d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a519190614f11565b6002546003549192505f917dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911690611aa0906dffffffffffffffffffffffffffff16611a9b6112af565b613ab8565b611aaa9190614f55565b9050817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161115611afa5703919050565b505090565b5f610bbb7f0000000000000000000000000000000000000000000000000000000000000000613ac3565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260046020526040812081611b56611b9b565b60028301549091505f90611b7e9064ffffffffff808216916501000000000090041684613af4565b9150611b92905063ffffffff831682614f93565b95945050505050565b5f610bbb611bcb610bb67f0000000000000000000000000000000000000000000000000000000000000000613b7d565b610e10613ba8565b5f8033611bdf81612f8c565b611be833612fea565b335f908152600560205260409020805460018201547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16935065ffffffffffff81169064ffffffffff6601000000000000820416906b010000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff16878314611c99576040517fd148789900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f611ca261133b565b63ffffffff16830190508064ffffffffff16421015611cfb576040517fdddc549900000000000000000000000000000000000000000000000000000000815264ffffffffff821660048201526024015b60405180910390fd5b5f611d04610b89565b63ffffffff16820190508064ffffffffff16421115611d58576040517fa170e12000000000000000000000000000000000000000000000000000000000815264ffffffffff82166004820152602401611cf2565b5050611d643387613060565b335f90815260056020526040902080547fff0000000000000000000000000000000000000000000000000000000000000016815560010180547fffff000000000000000000000000000000000000000000000000000000000000169055611dca86613bc2565b600354604080516dffffffffffffffffffffffffffff80851682527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8b166020830152939a509290911691339165ffffffffffff8716917fc7f1a91b0a382c263a18fea7b2908a6fcd90ebf2a9fde4bdf483b8ecceff1311910160405180910390a36002546dffffffffffffffffffffffffffff828116818b160191611e8d907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16613bc2565b6dffffffffffffffffffffffffffff16820110611ed6576040517f1123990900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff928316179055335f908152600660205260409081902080547fffff0000000000000000000000000000000000000000000000000000000000008116938c167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918216018116939093179055517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015291891660248201527f000000000000000000000000000000000000000000000000000000000000000091909116906340c10f19906044015f604051808303815f87803b158015612003575f80fd5b505af1158015612015573d5f803e3d5ffd5b50505050612021612348565b50505050505050915091565b5f8161203881612f8c565b61204183612a36565b15612078576040517fe2a4b46500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61208183612b28565b5f61208b84611725565b9050612096816139d5565b600380547fffffffffffffffffffffffffffffffffffff000000000000000000000000000081166dffffffffffffffffffffffffffff918216859003909116179055600280547fffff00000000000000000000000000000000000000000000000000000000000081167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff91821684018216179091556040519082168152909350339073ffffffffffffffffffffffffffffffffffffffff8616907f441d4e9d05bbbeb9019e911d76bdd0bf9389b0755175567d4e59607be5348d9b9060200160405180910390a373ffffffffffffffffffffffffffffffffffffffff84165f908152600460209081526040808320838155600180820180547fffff0000000000000000000000000000000000000000000000000000000000009081169091556002830180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556005855283862080547fff0000000000000000000000000000000000000000000000000000000000000016815590910180548216905581547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017909155600690925290912080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86169216919091179055612299612348565b505050919050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604081205460ff166123175773ffffffffffffffffffffffffffffffffffffffff82165f908152600660205260409020547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166113e8565b5f92915050565b5f610bbb7f0000000000000000000000000000000000000000000000000000000000000000613bd4565b5f806123526119c2565b90507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81161561245d576040517f40c10f1900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000811660048301527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831660248301527f000000000000000000000000000000000000000000000000000000000000000016906340c10f19906044015f604051808303815f87803b158015612446575f80fd5b505af1158015612458573d5f803e3d5ffd5b505050505b612465613bff565b91507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b9f412b06040518163ffffffff1660e01b81526004016020604051808303815f875af11580156124d1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611afa9190614fb1565b5f3361250081612f8c565b825f03612539576040517faa58a19400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380547fffffffffffff000000000000ffffffffffffffffffffffffffffffffffffffff8116740100000000000000000000000000000000000000009182900465ffffffffffff90811660010190811690920217909155335f9081526004602052604081208054929450916201000090047dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16906125d586612d04565b60018401549091505f9061260a9083907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16614f55565b9050807dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1610156126b0576040517f10bb3f430000000000000000000000000000000000000000000000000000000081527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808316600483015284166024820152604401611cf2565b60028401805464ffffffffff42166f01000000000000000000000000000000027fffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffff9091161790556001840180547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8084167fffff00000000000000000000000000000000000000000000000000000000000092831617909255335f81815260076020908152604080832065ffffffffffff8d16845290915281208054948716949093169390931790915561278191613060565b6040517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83168152339065ffffffffffff8816907f83f709bc37ea6de507e30b18311aa7a86c08833fa447f2c76ccc463c8936c4999060200160405180910390a35050505050919050565b5f610bbb610bb67f0000000000000000000000000000000000000000000000000000000000000000613d4f565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260046020526040812054610100900460ff166128b35773ffffffffffffffffffffffffffffffffffffffff83165f9081526007602052604081209061287684613d7a565b65ffffffffffff16815260208101919091526040015f20547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166128b5565b5f5b9392505050565b5f806128e9846128d36128ce86612d04565b613dbb565b6dffffffffffffffffffffffffffff1685610ced565b909590945092505050565b5f6128fe33612ace565b61290661165e565b73ffffffffffffffffffffffffffffffffffffffff83165f8181526004602090815260409182902060020180547fffffffffffffffffffffffffffffffffff0000000000ffffffffffffffffffff166a010000000000000000000063ffffffff96909616420164ffffffffff811696870291909117909155915193845290935090917f1ac7b35bca40be2823e4880f1b2e9ef02fa4c7bd62aed73c2ea2959232a1f9f5910160405180910390a2919050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260046020526040812054610100900460ff166123175773ffffffffffffffffffffffffffffffffffffffff82165f908152600460205260409020600101547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166113e8565b5f6113e87f000000000000000000000000000000000000000000000000000000000000000083613dcd565b6002545f907dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16612a8e6119a4565b01905090565b5f6113e8827f6d696e745f74746c000000000000000000000000000000000000000000000000613df9565b5f6113e88263ffffffff613e88565b612ad7816113bd565b612b25576040517ff731555300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82166004820152602401611cf2565b50565b5f612b3282611725565b9050806dffffffffffffffffffffffffffff165f03612b4f575050565b73ffffffffffffffffffffffffffffffffffffffff82165f90815260046020526040812060028101549091908190612ba29064ffffffffff8082169165010000000000900416612b9d611b9b565b613af4565b915091508164ffffffffff165f03612bbb575050505050565b808360020160056101000a81548164ffffffffff021916908364ffffffffff1602179055505f612c0d868464ffffffffff16876dffffffffffffffffffffffffffff16612c089190614fe0565b613e96565b9050806dffffffffffffffffffffffffffff165f03612c2e57505050505050565b8573ffffffffffffffffffffffffffffffffffffffff167f4fb8bb7b0278c9f68d34ce501b521ecd2e3c1bc48fe37eda47db36da6defc7ef84612c70846139d5565b6040805164ffffffffff90931683527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90911660208301520160405180910390a2505050505050565b5f6dffffffffffffffffffffffffffff821115612d00576040517fca21dbd100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5090565b5f7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115612d00576040517f2a49c10d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80612d71612d6b86611725565b85613ff6565b9150612d7c826139d5565b9050827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161115612e22576040517f37666f1d0000000000000000000000000000000000000000000000000000000081527dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808316600483015284166024820152604401611cf2565b73ffffffffffffffffffffffffffffffffffffffff949094165f90815260066020526040902080547fffff00000000000000000000000000000000000000000000000000000000000081166dffffffffffffffffffffffffffff8481167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9384160390921617909155600380547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000811690831684900390921691909117905593915050565b5f612ef8612ef2846122a1565b83614024565b73ffffffffffffffffffffffffffffffffffffffff9093165f90815260066020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80821686900381167fffff0000000000000000000000000000000000000000000000000000000000009283161790925560028054808416879003909316929091169190911790555090919050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526004602052604090205460ff16612b25576040517f7bcd1d8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81165f908152600460205260409020600201546a0100000000000000000000900464ffffffffff16421015612b25576040517f1526e62e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f61306a8361179f565b90505f827dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff166130978561168b565b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16019050818111156130fe576040517f5033ec120000000000000000000000000000000000000000000000000000000081526004810182905260248101839052604401611cf2565b50505050565b5f61271063ffffffff831664e8d4a5100002611819565b5f6128b56301e1338067ffffffffffffffff851663ffffffff85160204614072565b5f64e8d4a510006fffffffffffffffffffffffffffffffff841665ffffffffffff84160264e8d4a50fff015b049392505050565b5f6113e8826fffffffffffffffffffffffffffffffff613e88565b5f6113e8827f6d696e745f64656c617900000000000000000000000000000000000000000000613df9565b5f7f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f5f1b60016040516131ea919061501e565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b5f6128b5837f76616c696461746f727300000000000000000000000000000000000000000000846140eb565b5f6113e8827f6d696e745f726174696f00000000000000000000000000000000000000000000613df9565b5f8163ffffffff168363ffffffff16106132c357816128b5565b5090919050565b425f805b83811015613440575f8111801561336057508888600183038181106132f5576132f56150f3565b905060200201602081019061330a9190614b98565b73ffffffffffffffffffffffffffffffffffffffff16898983818110613332576133326150f3565b90506020020160208101906133479190614b98565b73ffffffffffffffffffffffffffffffffffffffff1611155b15613397576040517f139f3c9200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6134088e8e8e8e8e8e8e888181106133b1576133b16150f3565b90506020020160208101906133c69190614b98565b8d8d898181106133d8576133d86150f3565b905060200201358c8c8a8181106133f1576133f16150f3565b90506020028101906134039190615120565b61418b565b156134385761342f83888884818110613423576134236150f3565b9050602002013561434d565b92508160010191505b6001016132ce565b505f61344a61231e565b905080821015613490576040517f74e8306f0000000000000000000000000000000000000000000000000000000081526004810183905260248101829052604401611cf2565b50509b9a5050505050505050505050565b5f6134ab83611725565b9050806dffffffffffffffffffffffffffff165f036134c957505050565b5f6134d38461179f565b90507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81106135005750505050565b5f61350a82613dbb565b9050826dffffffffffffffffffffffffffff16816dffffffffffffffffffffffffffff161061353a575050505050565b73ffffffffffffffffffffffffffffffffffffffff85165f90815260046020526040812060028101549091906135839064ffffffffff8082169165010000000000900416614369565b90508064ffffffffff168664ffffffffff16116135a35750505050505050565b8086038386035f6135f98a6135b6611b9b565b63ffffffff168564ffffffffff1685026dffffffffffffffffffffffffffff16816135e3576135e3614e93565b046dffffffffffffffffffffffffffff16613e96565b9050806dffffffffffffffffffffffffffff165f0361361e5750505050505050505050565b8973ffffffffffffffffffffffffffffffffffffffff167fadbe0a005ef4d2903a69fd3053b1c8dfc083430632f549a92a1d3bc648104ae361365f846139d5565b85613669856139d5565b604080517dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff948516815264ffffffffff93909316602084015292168183015290519081900360600190a250505050505050505050565b5f805b828110156137e9575f6136ea8585848181106136de576136de6150f3565b90506020020135613d7a565b73ffffffffffffffffffffffffffffffffffffffff87165f90815260076020908152604080832065ffffffffffff851684529091528120549192507dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116908190036137565750506137e1565b73ffffffffffffffffffffffffffffffffffffffff87165f81815260076020908152604080832065ffffffffffff8716808552925280832080547fffff000000000000000000000000000000000000000000000000000000000000169055519684019690917f7318b8ec2c2570ee6068ac690bbda62f9d13d38d52e36e23e0885101a5ffab0791a350505b6001016136c0565b5073ffffffffffffffffffffffffffffffffffffffff9093165f90815260046020526040902060010180547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808216869003167fffff0000000000000000000000000000000000000000000000000000000000009091161790555090919050565b73ffffffffffffffffffffffffffffffffffffffff83165f90815260046020526040812060028101549091906138dd906138bf9064ffffffffff808216916f01000000000000000000000000000000900416614369565b6138d66138ca611b9b565b63ffffffff164261434d565b4203614369565b90508064ffffffffff168364ffffffffff1611613937576040517f17ea884500000000000000000000000000000000000000000000000000000000815264ffffffffff808516600483015282166024820152604401611cf2565b5080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff909316620100000261ffff9093169290921782556002909101805464ffffffffff9092167fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090921691909117905550565b5f6113e8827f6d696e7465725f667265657a655f74696d650000000000000000000000000000613df9565b5f6113e8826139e26112af565b614385565b5f61171a7f22b57ca54bd15c6234b29e87aa1d76a0841b6e65e63d7acacef989de0bc3ff9e5f1b88888888604051602001613a23929190615181565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815282825280516020918201209083019590955273ffffffffffffffffffffffffffffffffffffffff909316928101929092526060820152608081019190915260a0810185905260c0810184905260e00160405160208183030381529060405280519060200120614390565b5f6128b583836143f1565b5f6113e8613af1837f6d696e7465725f726174655f6d6f64656c000000000000000000000000000000613df9565b90565b5f805f613b018686614369565b90508564ffffffffff165f03613b1b575f92509050613b75565b5f613b2682426151c1565b90508463ffffffff168164ffffffffff161015613b4857505f92509050613b75565b8463ffffffff168164ffffffffff1681613b6457613b64614e93565b0493505063ffffffff841683020190505b935093915050565b5f6113e8827f7570646174655f636f6c6c61746572616c5f696e74657276616c000000000000613df9565b5f8163ffffffff168363ffffffff16116132c357816128b5565b5f6113e882613bcf6112af565b614422565b5f6113e8827f7570646174655f636f6c6c61746572616c5f7468726573686f6c640000000000613df9565b5f80613c0961442d565b5f5490915064ffffffffff740100000000000000000000000000000000000000009091041642148015613c5957505f5463ffffffff82811670010000000000000000000000000000000090920416145b15613c775750505f546fffffffffffffffffffffffffffffffff1690565b613c7f6112af565b5f80546fffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff0000000000000000000000000000000000000000909116811770010000000000000000000000000000000063ffffffff8616908102919091177fffffffffffffff0000000000ffffffffffffffffffffffffffffffffffffffff16740100000000000000000000000000000000000000004264ffffffffff16021783556040519395509290917f8f9a1730052b867fdeb484b52fbc51e9bb62830781805ac95c382bbf8ea717a291a35090565b5f6113e8827f70656e616c74795f726174650000000000000000000000000000000000000000613df9565b5f65ffffffffffff821115612d00576040517f069c6d4d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6113e882613dc86112af565b61452d565b5f6128b5837f6d696e7465727300000000000000000000000000000000000000000000000000846140eb565b6040517f8eaa6ac0000000000000000000000000000000000000000000000000000000008152600481018290525f9073ffffffffffffffffffffffffffffffffffffffff841690638eaa6ac090602401602060405180830381865afa158015613e64573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906128b59190614f11565b5f8183106132c357816128b5565b5f8172ffffffffffffffffffffffffffffffffffffff165f03613eba57505f6113e8565b5f613ec36127ea565b90508063ffffffff165f03613edb575f9150506113e8565b60035461271063ffffffff831672ffffffffffffffffffffffffffffffffffffff86160204906dffffffffffffffffffffffffffff908116820190811115613f3a5750506003546dffffffffffffffffffffffffffff90811681038116905b600380547fffffffffffffffffffffffffffffffffffff0000000000000000000000000000166dffffffffffffffffffffffffffff92831617905573ffffffffffffffffffffffffffffffffffffffff959095165f90815260066020526040902080547fffff00000000000000000000000000000000000000000000000000000000000081169683167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff918216011695909517909455509192915050565b5f816dffffffffffffffffffffffffffff16836dffffffffffffffffffffffffffff16106132c357816128b5565b5f817dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16837dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16106132c357816128b5565b5f68ffffffffffffffffff821680026123288102642e90edd000820464174876e800830402016c010f6b2be4706a13fc200000000182633b9aca008304669536c708910000018568ffffffffffffffffff1602905080820381830164e8d4a5100002816140e1576140e1614e93565b0495945050505050565b6040517fd7d1c1c00000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff82811660248301525f919085169063d7d1c1c090604401602060405180830381865afa15801561415f573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061418391906151df565b949350505050565b5f835f036141c5576040517fda16d76700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4264ffffffffff16841115614206576040517f0ff02cef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff808b165f90815260086020908152604080832093891683529290522054808511614297576040517f2e7a0bcb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871660048201526024810186905260448101829052606401611cf2565b6142a0866113bd565b6142ad575f915050614340565b6142fa866142bf8d8d8d8d8d8c6139e7565b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061453892505050565b614307575f915050614340565b505073ffffffffffffffffffffffffffffffffffffffff808a165f90815260086020908152604080832093881683529290522083905560015b9998505050505050505050565b5f8164ffffffffff168364ffffffffff16106132c357816128b5565b5f8164ffffffffff168364ffffffffff16116132c357816128b5565b5f6128b58383614555565b5f614399611368565b6040517f19010000000000000000000000000000000000000000000000000000000000006020820152602281019190915260428101839052606201604051602081830303815290604052805190602001209050919050565b5f64e8d4a510006dffffffffffffffffffffffffffff84166fffffffffffffffffffffffffffffffff841602613169565b5f6128b5838361458d565b5f805f614438611aff565b60408051600481526024810182526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f2c4e722e00000000000000000000000000000000000000000000000000000000179052905173ffffffffffffffffffffffffffffffffffffffff92909216916144b491906151fe565b5f60405180830381855afa9150503d805f81146144ec576040519150601f19603f3d011682016040523d82523d5f602084013e6144f1565b606091505b509150915081801561450557506020815110155b61450f575f614526565b61452681806020019051810190610bb69190614f11565b9250505090565b5f6128b5838361464e565b5f6145448484846146e5565b806141835750614183848484614734565b5f64e8d4a510006dffffffffffffffffffffffffffff84166fffffffffffffffffffffffffffffffff84160264e8d4a50fff01613169565b5f816fffffffffffffffffffffffffffffffff165f036145d9576040517f23d359a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128b56fffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861664e8d4a51000028201018161464857614648614e93565b04612cb7565b5f816fffffffffffffffffffffffffffffffff165f0361469a576040517f23d359a300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6128b56fffffffffffffffffffffffffffffffff83167dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff851664e8d4a51000028161464857614648614e93565b5f815160400361470e57602082015160408301516147058686848461487d565b925050506128b5565b5f61471a8585856148a6565b600581111561472b5761472b615219565b14949350505050565b5f805f8573ffffffffffffffffffffffffffffffffffffffff168585604051602401614761929190615246565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1626ba7e00000000000000000000000000000000000000000000000000000000179052516147e291906151fe565b5f60405180830381855afa9150503d805f811461481a576040519150601f19603f3d011682016040523d82523d5f602084013e61481f565b606091505b509150915081801561483357506020815110155b8015614873575080517f1626ba7e00000000000000000000000000000000000000000000000000000000906148719083016020908101908401614f11565b145b9695505050505050565b5f8061488b868686866148e0565b600581111561489c5761489c615219565b1495945050505050565b5f805f6148b3858561491b565b90925090505f8260058111156148cb576148cb615219565b146148d65781614873565b614873868261495f565b5f805f6148ee86868661499a565b90925090505f82600581111561490657614906615219565b14614911578161171a565b61171a878261495f565b5f8082516041146149315750600290505f614958565b6020830151604084015160608501515f1a9190614950878484846149e1565b945094505050505b9250929050565b5f8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146128b35760056128b5565b5f80601b60ff84901c017f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84166149d3878388846149e1565b935093505050935093915050565b5f807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115614a165750600390505f614ae5565b8460ff16601b14158015614a2e57508460ff16601c14155b15614a3e5750600490505f614ae5565b604080515f81526020810180835288905260ff871691810191909152606081018590526080810184905260019060a0016020604051602081039080840390855afa158015614a8e573d5f803e3d5ffd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615614adc575f81614ae0565b60015f5b915091505b94509492505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114614b11575f80fd5b919050565b5f8060408385031215614b27575f80fd5b614b3083614aee565b946020939093013593505050565b5f805f60608486031215614b50575f80fd5b614b5984614aee565b95602085013595506040909401359392505050565b5f8060408385031215614b7f575f80fd5b82359150614b8f60208401614aee565b90509250929050565b5f60208284031215614ba8575f80fd5b6128b582614aee565b5f8083601f840112614bc1575f80fd5b50813567ffffffffffffffff811115614bd8575f80fd5b6020830191508360208260051b8501011115614958575f80fd5b5f805f805f805f805f8060c08b8d031215614c0b575f80fd5b8a35995060208b013567ffffffffffffffff80821115614c29575f80fd5b614c358e838f01614bb1565b909b50995060408d0135985060608d0135915080821115614c54575f80fd5b614c608e838f01614bb1565b909850965060808d0135915080821115614c78575f80fd5b614c848e838f01614bb1565b909650945060a08d0135915080821115614c9c575f80fd5b50614ca98d828e01614bb1565b915080935050809150509295989b9194979a5092959850565b5f805f805f8060a08789031215614cd7575f80fd5b614ce087614aee565b955060208701359450604087013567ffffffffffffffff811115614d02575f80fd5b614d0e89828a01614bb1565b979a9699509760608101359660809091013595509350505050565b5f5b83811015614d43578181015183820152602001614d2b565b50505f910152565b5f8151808452614d62816020860160208601614d29565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b7fff00000000000000000000000000000000000000000000000000000000000000881681525f602060e06020840152614dd060e084018a614d4b565b8381036040850152614de2818a614d4b565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825260208088019350909101905f5b81811015614e4257835183529284019291840191600101614e26565b50909c9b505050505050505050505050565b5f60208284031215614e64575f80fd5b5035919050565b5f8060408385031215614e7c575f80fd5b614e8583614aee565b9150614b8f60208401614aee565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b600181811c90821680614ed457607f821691505b602082108103614f0b577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b5f60208284031215614f21575f80fd5b5051919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff818116838216019080821115614f8c57614f8c614f28565b5092915050565b64ffffffffff818116838216019080821115614f8c57614f8c614f28565b5f60208284031215614fc1575f80fd5b81516fffffffffffffffffffffffffffffffff811681146128b5575f80fd5b72ffffffffffffffffffffffffffffffffffffff82811682821681810283169291811582850482141761501557615015614f28565b50505092915050565b5f8083545f60018260011c9150600183168061503b57607f831692505b60208084108203615073577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b81801561508757600181146150ba576150e5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528415158502890196506150e5565b5f8a8152602090205f5b868110156150dd5781548b8201529085019083016150c4565b505084890196505b509498975050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615153575f80fd5b83018035915067ffffffffffffffff82111561516d575f80fd5b602001915036819003821315614958575f80fd5b5f7f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156151ae575f80fd5b8260051b80858437919091019392505050565b64ffffffffff828116828216039080821115614f8c57614f8c614f28565b5f602082840312156151ef575f80fd5b815180151581146128b5575f80fd5b5f825161520f818460208701614d29565b9190910192915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b828152604060208201525f6141836040830184614d4b56fea2646970667358221220decb3a3a9db6ebea55049121aa2d482d98ca58a9ca23cfccb51d08010c78d75664736f6c63430008170033000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b","name":"MinterGateway","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"shanghai","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"lib/protocol/lib/common/src/ERC712Extended.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { IERC712 } from \"./interfaces/IERC712.sol\";\nimport { IERC712Extended } from \"./interfaces/IERC712Extended.sol\";\n\nimport { SignatureChecker } from \"./libs/SignatureChecker.sol\";\n\n/**\n * @title  Typed structured data hashing and signing via EIP-712, extended by EIP-5267.\n * @author M^0 Labs\n * @dev    An abstract implementation to satisfy EIP-712: https://eips.ethereum.org/EIPS/eip-712\n */\nabstract contract ERC712Extended is IERC712Extended {\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    /// @dev Initial Chain ID set at deployment.\n    uint256 internal immutable _INITIAL_CHAIN_ID;\n\n    /// @dev Initial EIP-712 domain separator set at deployment.\n    bytes32 internal immutable _INITIAL_DOMAIN_SEPARATOR;\n\n    /// @dev The name of the contract.\n    string internal _name;\n\n    /* ============ Constructor ============ */\n\n    /**\n     * @notice Constructs the EIP-712 domain separator.\n     * @param  name_ The name of the contract.\n     */\n    constructor(string memory name_) {\n        _name = name_;\n\n        _INITIAL_CHAIN_ID = block.chainid;\n        _INITIAL_DOMAIN_SEPARATOR = _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            _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        return block.chainid == _INITIAL_CHAIN_ID ? _INITIAL_DOMAIN_SEPARATOR : _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(_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/protocol/lib/common/src/interfaces/IERC1271.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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/protocol/lib/common/src/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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/protocol/lib/common/src/interfaces/IERC20Extended.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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 block number 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 block number 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/protocol/lib/common/src/interfaces/IERC3009.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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/protocol/lib/common/src/interfaces/IERC712.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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 deadline of the signature.\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":"lib/protocol/lib/common/src/interfaces/IERC712Extended.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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":"lib/protocol/lib/common/src/interfaces/IStatefulERC712.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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/protocol/lib/common/src/libs/SignatureChecker.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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/protocol/lib/common/src/libs/UIntMath.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\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 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 given uint256 value to a uint16,\n     *         ensuring that it is less than or equal to the maximum uint16 value.\n     * @param  n The value to check.\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 given uint256 value to a uint40,\n     *         ensuring that it is less than or equal to the maximum uint40 value.\n     * @param  n The value to check.\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 given uint256 value to a uint48,\n     *         ensuring that it is less than or equal to the maximum uint48 value.\n     * @param  n The value to check.\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 given uint256 value to a uint112,\n     *         ensuring that it is less than or equal to the maximum uint112 value.\n     * @param  n The value to check.\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 given uint256 value to a uint128,\n     *         ensuring that it is less than or equal to the maximum uint128 value.\n     * @param  n The value to check.\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 given uint256 value to a uint240,\n     *         ensuring that it is less than or equal to the maximum uint240 value.\n     * @param  n The value to check.\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 given uint256 value to the maximum uint32 value.\n     * @param  n The value to check.\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 given uint256 value to the maximum uint112 value.\n     * @param  n The value to check.\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 given uint256 value to the maximum uint128 value.\n     * @param  n The value to check.\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 given uint256 value to the maximum uint240 value.\n     * @param  n The value to check.\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 check.\n     * @param  b_  Value to check.\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 check.\n     * @param  b_  Value to check.\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 uint32 values and returns the lesser one.\n     * @param  a_  Value to check.\n     * @param  b_  Value to check.\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 check.\n     * @param  b_  Value to check.\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 check.\n     * @param  b_  Value to check.\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 check.\n     * @param  b_  Value to check.\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 check.\n     * @param  b_  Value to check.\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/protocol/src/abstract/ContinuousIndexing.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { IContinuousIndexing } from \"../interfaces/IContinuousIndexing.sol\";\n\nimport { ContinuousIndexingMath } from \"../libs/ContinuousIndexingMath.sol\";\n\n/**\n * @title Abstract Continuous Indexing Contract to handle rate/index updates in inheriting contracts.\n * @author M^0 Labs\n */\nabstract contract ContinuousIndexing is IContinuousIndexing {\n    /* ============ Variables ============ */\n\n    /// @inheritdoc IContinuousIndexing\n    uint128 public latestIndex;\n\n    /// @dev The latest updated rate.\n    uint32 internal _latestRate;\n\n    /// @inheritdoc IContinuousIndexing\n    uint40 public latestUpdateTimestamp;\n\n    /* ============ Constructor ============ */\n\n    /// @notice Constructs the ContinuousIndexing contract.\n    constructor() {\n        latestIndex = ContinuousIndexingMath.EXP_SCALED_ONE;\n        latestUpdateTimestamp = uint40(block.timestamp);\n    }\n\n    /* ============ Interactive Functions ============ */\n\n    /// @inheritdoc IContinuousIndexing\n    function updateIndex() public virtual returns (uint128 currentIndex_) {\n        // NOTE: `_rate()` can depend indirectly on `latestIndex` and `latestUpdateTimestamp`, if the RateModel\n        //       depends on earning balances/supply, which depends on `currentIndex()`, so only update them after this.\n        uint32 rate_ = _rate();\n\n        if (latestUpdateTimestamp == block.timestamp && _latestRate == rate_) return latestIndex;\n\n        // NOTE: `currentIndex()` depends on `_latestRate`, so only update it after this.\n        latestIndex = currentIndex_ = currentIndex();\n        _latestRate = rate_;\n        latestUpdateTimestamp = uint40(block.timestamp);\n\n        emit IndexUpdated(currentIndex_, rate_);\n    }\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @inheritdoc IContinuousIndexing\n    function currentIndex() public view virtual returns (uint128);\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @dev    Returns the principal amount (rounded down) given the present amount, using the current index.\n     * @param  presentAmount_ The present amount.\n     * @return The principal amount rounded down.\n     */\n    function _getPrincipalAmountRoundedDown(uint240 presentAmount_) internal view returns (uint112) {\n        return _getPrincipalAmountRoundedDown(presentAmount_, currentIndex());\n    }\n\n    /**\n     * @dev    Returns the principal amount (rounded up) given the present amount and an index.\n     * @param  presentAmount_ The present amount.\n     * @return The principal amount rounded up.\n     */\n    function _getPrincipalAmountRoundedUp(uint240 presentAmount_) internal view returns (uint112) {\n        return _getPrincipalAmountRoundedUp(presentAmount_, currentIndex());\n    }\n\n    /**\n     * @dev    Returns the present amount (rounded down) given the principal amount and an index.\n     * @param  principalAmount_ The principal amount.\n     * @param  index_           An index.\n     * @return The present amount rounded down.\n     */\n    function _getPresentAmountRoundedDown(uint112 principalAmount_, uint128 index_) internal pure returns (uint240) {\n        return ContinuousIndexingMath.multiplyDown(principalAmount_, index_);\n    }\n\n    /**\n     * @dev    Returns the present amount (rounded up) given the principal amount and an index.\n     * @param  principalAmount_ The principal amount.\n     * @param  index_           An index.\n     * @return The present amount rounded up.\n     */\n    function _getPresentAmountRoundedUp(uint112 principalAmount_, uint128 index_) internal pure returns (uint240) {\n        return ContinuousIndexingMath.multiplyUp(principalAmount_, index_);\n    }\n\n    /**\n     * @dev    Returns the principal amount given the present amount, using the current index.\n     * @param  presentAmount_ The present amount.\n     * @param  index_         An index.\n     * @return The principal amount rounded down.\n     */\n    function _getPrincipalAmountRoundedDown(uint240 presentAmount_, uint128 index_) internal pure returns (uint112) {\n        return ContinuousIndexingMath.divideDown(presentAmount_, index_);\n    }\n\n    /**\n     * @dev    Returns the principal amount given the present amount, using the current index.\n     * @param  presentAmount_ The present amount.\n     * @param  index_         An index.\n     * @return The principal amount rounded up.\n     */\n    function _getPrincipalAmountRoundedUp(uint240 presentAmount_, uint128 index_) internal pure returns (uint112) {\n        return ContinuousIndexingMath.divideUp(presentAmount_, index_);\n    }\n\n    /// @dev To be overridden by the inheriting contract to return the current rate.\n    function _rate() internal view virtual returns (uint32);\n}\n"},{"file_path":"lib/protocol/src/interfaces/IContinuousIndexing.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\n/**\n * @title  Continuous Indexing Interface.\n * @author M^0 Labs\n */\ninterface IContinuousIndexing {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when the index is updated.\n     * @param  index The new index.\n     * @param  rate  The current rate.\n     */\n    event IndexUpdated(uint128 indexed index, uint32 indexed rate);\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Updates the latest index and latest accrual time in storage.\n     * @return index The new stored index for computing present amounts from principal amounts.\n     */\n    function updateIndex() external returns (uint128);\n\n    /* ============ View/Pure Functions ============ */\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 latest updated index.\n    function latestIndex() external view returns (uint128);\n\n    /// @notice The latest timestamp when the index was updated.\n    function latestUpdateTimestamp() external view returns (uint40);\n}\n"},{"file_path":"lib/protocol/src/interfaces/IMToken.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { IERC20Extended } from \"../../lib/common/src/interfaces/IERC20Extended.sol\";\n\nimport { IContinuousIndexing } from \"./IContinuousIndexing.sol\";\n\n/**\n * @title  M Token Interface.\n * @author M^0 Labs\n */\ninterface IMToken is IContinuousIndexing, IERC20Extended {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when account starts being an M earner.\n     * @param  account The account that started earning.\n     */\n    event StartedEarning(address indexed account);\n\n    /**\n     * @notice Emitted when account stops being an M earner.\n     * @param  account The account that stopped earning.\n     */\n    event StoppedEarning(address indexed account);\n\n    /* ============ Custom Errors ============ */\n\n    /**\n     * @notice Emitted when there is insufficient balance to decrement from `account`.\n     * @param  account     The account with insufficient balance.\n     * @param  rawBalance  The raw balance of the account.\n     * @param  amount      The amount to decrement the `rawBalance` by.\n     */\n    error InsufficientBalance(address account, uint256 rawBalance, uint256 amount);\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    /// @notice Emitted when calling `mint`, `burn` not by Minter Gateway.\n    error NotMinterGateway();\n\n    /// @notice Emitted when principal of total supply (earning and non-earning) will overflow a `type(uint112).max`.\n    error OverflowsPrincipalOfTotalSupply();\n\n    /// @notice Emitted in constructor if Minter Gateway is 0x0.\n    error ZeroMinterGateway();\n\n    /// @notice Emitted in constructor if TTG Registrar is 0x0.\n    error ZeroTTGRegistrar();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Mints tokens.\n     * @param  account The address of account to mint to.\n     * @param  amount  The amount of M Token to mint.\n     */\n    function mint(address account, uint256 amount) external;\n\n    /**\n     * @notice Burns tokens.\n     * @param  account The address of account to burn from.\n     * @param  amount  The amount of M Token to burn.\n     */\n    function burn(address account, uint256 amount) external;\n\n    /// @notice Starts earning for caller if allowed by TTG.\n    function startEarning() external;\n\n    /// @notice Stops earning for caller.\n    function stopEarning() 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    /// @notice The address of the Minter Gateway contract.\n    function minterGateway() external view returns (address);\n\n    /// @notice The address of the TTG Registrar contract.\n    function ttgRegistrar() external view returns (address);\n\n    /// @notice The address of TTG approved earner rate model.\n    function rateModel() external view returns (address);\n\n    /// @notice The current value of earner rate in basis points.\n    function earnerRate() external view returns (uint32);\n\n    /**\n     * @notice The principal of an earner M token balance.\n     * @param  account The account to get the principal balance of.\n     * @return The principal balance of the account.\n     */\n    function principalBalanceOf(address account) external view returns (uint240);\n\n    /// @notice The principal of the total earning supply of M Token.\n    function principalOfTotalEarningSupply() external view returns (uint112);\n\n    /// @notice The total earning supply of M Token.\n    function totalEarningSupply() external view returns (uint240);\n\n    /// @notice The total non-earning supply of M Token.\n    function totalNonEarningSupply() external view returns (uint240);\n\n    /**\n     * @notice Checks if account is an earner.\n     * @param  account The account to check.\n     * @return True if account is an earner, false otherwise.\n     */\n    function isEarning(address account) external view returns (bool);\n}\n"},{"file_path":"lib/protocol/src/interfaces/IMinterGateway.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { IERC712 } from \"../../lib/common/src/interfaces/IERC712.sol\";\n\nimport { IContinuousIndexing } from \"./IContinuousIndexing.sol\";\n\n/**\n * @title  Minter Gateway Interface.\n * @author M^0 Labs\n */\ninterface IMinterGateway is IContinuousIndexing, IERC712 {\n    /* ============ Events ============ */\n\n    /**\n     * @notice Emitted when M tokens are burned and an inactive minter's owed M balance decreased.\n     * @param  minter The address of the minter.\n     * @param  amount The amount of M tokens burned.\n     * @param  payer  The address of the payer.\n     */\n    event BurnExecuted(address indexed minter, uint240 amount, address indexed payer);\n\n    /**\n     * @notice Emitted when M tokens are burned and an active minter's owed M balance decreased.\n     * @param  minter          The address of the minter.\n     * @param  principalAmount The principal amount of M tokens burned.\n     * @param  amount          The amount of M tokens burned.\n     * @param  payer           The address of the payer.\n     */\n    event BurnExecuted(address indexed minter, uint112 principalAmount, uint240 amount, address indexed payer);\n\n    /**\n     * @notice Emitted when a minter's collateral is updated.\n     * @param  minter                           Address of the minter\n     * @param  collateral                       The latest amount of collateral\n     * @param  totalResolvedCollateralRetrieval The total collateral amount of outstanding retrievals resolved.\n     * @param  metadataHash                     The hash of some metadata reserved for future informational use.\n     * @param  timestamp                        The timestamp of the collateral update,\n     *                                          minimum of given validators' signatures.\n     */\n    event CollateralUpdated(\n        address indexed minter,\n        uint240 collateral,\n        uint240 totalResolvedCollateralRetrieval,\n        bytes32 indexed metadataHash,\n        uint40 timestamp\n    );\n\n    /**\n     * @notice Emitted when a minter is activated.\n     * @param  minter Address of the minter that was activated\n     * @param  caller Address who called the function\n     */\n    event MinterActivated(address indexed minter, address indexed caller);\n\n    /**\n     * @notice Emitted when a minter is deactivated.\n     * @param  minter        Address of the minter that was deactivated.\n     * @param  inactiveOwedM Amount of M tokens owed by the minter (in an inactive state).\n     * @param  caller        Address who called the function.\n     */\n    event MinterDeactivated(address indexed minter, uint240 inactiveOwedM, address indexed caller);\n\n    /**\n     * @notice Emitted when a minter is frozen.\n     * @param  minter      Address of the minter that was frozen\n     * @param  frozenUntil Timestamp until the minter is frozen\n     */\n    event MinterFrozen(address indexed minter, uint40 frozenUntil);\n\n    /**\n     * @notice Emitted when a mint proposal is canceled.\n     * @param  mintId    The id of the canceled mint proposal.\n     * @param  minter    The address of the minter for which the mint was canceled.\n     * @param  canceller The address of the validator who canceled the mint proposal.\n     */\n    event MintCanceled(uint48 indexed mintId, address indexed minter, address indexed canceller);\n\n    /**\n     * @notice Emitted when a mint proposal is executed.\n     * @param  mintId          The id of the executed mint proposal.\n     * @param  minter          The address of the minter that executed the mint.\n     * @param  principalAmount The principal amount of M tokens minted.\n     * @param  amount          The amount of M tokens minted.\n     */\n    event MintExecuted(uint48 indexed mintId, address indexed minter, uint112 principalAmount, uint240 amount);\n\n    /**\n     * @notice Emitted when a mint proposal is created.\n     * @param  mintId      The id of mint proposal.\n     * @param  minter      The address of the minter that proposed the mint.\n     * @param  amount      The amount of M tokens to mint.\n     * @param  destination The address to mint to.\n     */\n    event MintProposed(uint48 indexed mintId, address indexed minter, uint240 amount, address indexed destination);\n\n    /**\n     * @notice Emitted when a penalty is imposed on `minter` for missed update collateral intervals.\n     * @param  minter          The address of the minter.\n     * @param  missedIntervals The number of update intervals missed.\n     * @param  penaltyAmount   The present amount of penalty charge.\n     */\n    event MissedIntervalsPenaltyImposed(address indexed minter, uint40 missedIntervals, uint240 penaltyAmount);\n\n    /**\n     * @notice Emitted when a penalty is imposed on `minter` for undercollateralization.\n     * @param  minter        The address of the minter.\n     * @param  excessOwedM   The present amount of owed M in excess of allowed owed M.\n     * @param  timeSpan      The span of time over which the undercollateralization penalty was applied.\n     * @param  penaltyAmount The present amount of penalty charge.\n     */\n    event UndercollateralizedPenaltyImposed(\n        address indexed minter,\n        uint240 excessOwedM,\n        uint40 timeSpan,\n        uint240 penaltyAmount\n    );\n\n    /**\n     * @notice Emitted when a collateral retrieval proposal is created.\n     * @param  retrievalId The id of retrieval proposal.\n     * @param  minter      The address of the minter.\n     * @param  amount      The amount of collateral to retrieve.\n     */\n    event RetrievalCreated(uint48 indexed retrievalId, address indexed minter, uint240 amount);\n\n    /**\n     * @notice Emitted when a collateral retrieval proposal is resolved.\n     * @param  retrievalId The id of retrieval proposal.\n     * @param  minter      The address of the minter.\n     */\n    event RetrievalResolved(uint48 indexed retrievalId, address indexed minter);\n\n    /* ============ Custom Errors ============ */\n\n    /// @notice Emitted when calling `activateMinter` with a minter who was previously deactivated.\n    error DeactivatedMinter();\n\n    /// @notice Emitted when repay will burn more M than the repay specified.\n    error ExceedsMaxRepayAmount(uint240 amount, uint240 maxAmount);\n\n    /// @notice Emitted when calling `mintM` with a proposal that was created more than `mintDelay + mintTTL` time ago.\n    error ExpiredMintProposal(uint40 deadline);\n\n    /// @notice Emitted when calling `mintM` or `proposeMint` by a minter who was frozen by validator.\n    error FrozenMinter();\n\n    /// @notice Emitted when calling `updateCollateral` with any validator timestamp in the future.\n    error FutureTimestamp();\n\n    /// @notice Emitted when calling a function only allowed for active minters.\n    error InactiveMinter();\n\n    /// @notice Emitted when calling `cancelMint` or `mintM` with invalid `mintId`.\n    error InvalidMintProposal();\n\n    /// @notice Emitted when calling `updateCollateral` if `validators` addresses are not ordered in ascending order.\n    error InvalidSignatureOrder();\n\n    /// @notice Emitted when calling `activateMinter` if minter was not approved by TTG.\n    error NotApprovedMinter();\n\n    /// @notice Emitted when calling `cancelMint` or `freezeMinter` if `validator` was not approved by TTG.\n    error NotApprovedValidator(address validator);\n\n    /// @notice Emitted when calling `updateCollateral` if `validatorThreshold` of signatures was not reached.\n    error NotEnoughValidSignatures(uint256 validSignatures, uint256 requiredThreshold);\n\n    /// @notice Emitted when principal of total owed M (active and inactive) will overflow a `type(uint112).max`.\n    error OverflowsPrincipalOfTotalOwedM();\n\n    /// @notice Emitted when calling `mintM` if `mintDelay` time has not passed yet.\n    error PendingMintProposal(uint40 activeTimestamp);\n\n    /// @notice Emitted when calling `proposeRetrieval` if sum of all outstanding retrievals\n    ///         Plus new proposed retrieval amount is greater than collateral.\n    error RetrievalsExceedCollateral(uint240 totalPendingRetrievals, uint240 collateral);\n\n    /// @notice Emitted when calling `updateCollateral`\n    ///         If `validators`, `signatures`, `timestamps` lengths do not match.\n    error SignatureArrayLengthsMismatch();\n\n    /// @notice Emitted when updating collateral with a timestamp earlier than allowed.\n    error StaleCollateralUpdate(uint40 newTimestamp, uint40 earliestAllowedTimestamp);\n\n    /// @notice Emitted when calling `updateCollateral` with any validator timestamp older than the last signature\n    ///         timestamp for that minter and validator.\n    error OutdatedValidatorTimestamp(address validator, uint256 timestamp, uint256 lastSignatureTimestamp);\n\n    /// @notice Emitted when calling `deactivateMinter` with a minter still approved in TTG Registrar.\n    error StillApprovedMinter();\n\n    /**\n     * @notice Emitted when calling `proposeMint`, `mintM`, `proposeRetrieval`\n     *         If minter position becomes undercollateralized.\n     * @dev    `activeOwedM` is a `uint256` because it may represent some resulting owed M from computations.\n     */\n    error Undercollateralized(uint256 activeOwedM, uint256 maxAllowedOwedM);\n\n    /// @notice Emitted when calling `burnM` if amount is 0.\n    error ZeroBurnAmount();\n\n    /// @notice Emitted in constructor if M Token is 0x0.\n    error ZeroMToken();\n\n    /// @notice Emitted when calling `proposeMint` if amount is 0.\n    error ZeroMintAmount();\n\n    /// @notice Emitted when calling `proposeMint` if destination is 0x0.\n    error ZeroMintDestination();\n\n    /// @notice Emitted when calling `proposeRetrieval` if collateral is 0.\n    error ZeroRetrievalAmount();\n\n    /// @notice Emitted in constructor if TTG Registrar is 0x0.\n    error ZeroTTGRegistrar();\n\n    /// @notice Emitted in constructor if TTG Distribution Vault is set to 0x0 in TTG Registrar.\n    error ZeroTTGVault();\n\n    /// @notice Emitted when calling `updateCollateral` with any validator timestamp of 0.\n    error ZeroTimestamp();\n\n    /* ============ Interactive Functions ============ */\n\n    /**\n     * @notice Updates collateral for minters\n     * @param  collateral   The amount of collateral\n     * @param  retrievalIds The list of active proposeRetrieval requests to close\n     * @param  metadataHash The hash of metadata of the collateral update, reserved for future informational use\n     * @param  validators   The list of validators\n     * @param  timestamps   The list of timestamps of validators' signatures\n     * @param  signatures   The list of signatures\n     * @return minTimestamp The minimum timestamp of all validators' signatures\n     */\n    function updateCollateral(\n        uint256 collateral,\n        uint256[] calldata retrievalIds,\n        bytes32 metadataHash,\n        address[] calldata validators,\n        uint256[] calldata timestamps,\n        bytes[] calldata signatures\n    ) external returns (uint40 minTimestamp);\n\n    /**\n     * @notice Proposes retrieval of minter's off-chain collateral\n     * @param  collateral  The amount of collateral to retrieve\n     * @return retrievalId The unique id of created retrieval proposal\n     */\n    function proposeRetrieval(uint256 collateral) external returns (uint48 retrievalId);\n\n    /**\n     * @notice Proposes minting of M tokens\n     * @param  amount      The amount of M tokens to mint\n     * @param  destination The address to mint to\n     * @return mintId      The unique id of created mint proposal\n     */\n    function proposeMint(uint256 amount, address destination) external returns (uint48 mintId);\n\n    /**\n     * @notice Executes minting of M tokens\n     * @param  mintId          The id of outstanding mint proposal for minter\n     * @return principalAmount The amount of principal of owed M minted.\n     * @return amount          The amount of M tokens minted.\n     */\n    function mintM(uint256 mintId) external returns (uint112 principalAmount, uint240 amount);\n\n    /**\n     * @notice Burns M tokens\n     * @dev    If amount to burn is greater than minter's owedM including penalties, burn all up to owedM.\n     * @param  minter          The address of the minter to burn M tokens for.\n     * @param  maxAmount       The max amount of M tokens to burn.\n     * @return principalAmount The amount of principal of owed M burned.\n     * @return amount          The amount of M tokens burned.\n     */\n    function burnM(address minter, uint256 maxAmount) external returns (uint112 principalAmount, uint240 amount);\n\n    /**\n     * @notice Burns M tokens\n     * @dev    If amount to burn is greater than minter's owedM including penalties, burn all up to owedM.\n     * @param  minter             The address of the minter to burn M tokens for.\n     * @param  maxPrincipalAmount The max amount of principal of owed M to burn.\n     * @param  maxAmount          The max amount of M tokens to burn.\n     * @return principalAmount    The amount of principal of owed M burned.\n     * @return amount             The amount of M tokens burned.\n     */\n    function burnM(\n        address minter,\n        uint256 maxPrincipalAmount,\n        uint256 maxAmount\n    ) external returns (uint112 principalAmount, uint240 amount);\n\n    /**\n     * @notice Cancels minting request for selected minter by validator\n     * @param  minter The address of the minter to cancelMint minting request for\n     * @param  mintId The id of outstanding mint request\n     */\n    function cancelMint(address minter, uint256 mintId) external;\n\n    /**\n     * @notice Freezes minter\n     * @param  minter      The address of the minter to freeze\n     * @return frozenUntil The timestamp until which minter is frozen\n     */\n    function freezeMinter(address minter) external returns (uint40 frozenUntil);\n\n    /**\n     * @notice Activate an approved minter.\n     * @dev    MUST revert if `minter` is not recorded as an approved minter in TTG Registrar.\n     * @dev    MUST revert if `minter` has been deactivated.\n     * @param  minter The address of the minter to activate\n     */\n    function activateMinter(address minter) external;\n\n    /**\n     * @notice Deactivates an active minter.\n     * @dev    MUST revert if the minter is still approved.\n     * @dev    MUST revert if the minter is not active.\n     * @param  minter        The address of the minter to deactivate.\n     * @return inactiveOwedM The inactive owed M for the deactivated minter.\n     */\n    function deactivateMinter(address minter) external returns (uint240 inactiveOwedM);\n\n    /* ============ View/Pure Functions ============ */\n\n    /// @notice The address of M token\n    function mToken() external view returns (address);\n\n    /// @notice The address of TTG Registrar contract.\n    function ttgRegistrar() external view returns (address);\n\n    /// @notice The address of TTG Vault contract.\n    function ttgVault() external view returns (address);\n\n    /// @notice The last saved value of Minter rate.\n    function minterRate() external view returns (uint32);\n\n    /// @notice The principal of total owed M for all active minters.\n    function principalOfTotalActiveOwedM() external view returns (uint112);\n\n    /// @notice The total owed M for all active minters.\n    function totalActiveOwedM() external view returns (uint240);\n\n    /// @notice The total owed M for all inactive minters.\n    function totalInactiveOwedM() external view returns (uint240);\n\n    /// @notice The total owed M for all minters.\n    function totalOwedM() external view returns (uint240);\n\n    /// @notice The difference between total owed M and M token total supply.\n    function excessOwedM() external view returns (uint240);\n\n    /// @notice The principal of active owed M of minter.\n    function principalOfActiveOwedMOf(address minter_) external view returns (uint112);\n\n    /// @notice The active owed M of minter.\n    function activeOwedMOf(address minter) external view returns (uint240);\n\n    /**\n     * @notice The max allowed active owed M of minter taking into account collateral amount and retrieval proposals.\n     * @dev    This is the only present value that requires a `uint256` since it is the result of a multiplication\n     *         between a `uint240` and a value that has a max of `65,000` (the mint ratio).\n     */\n    function maxAllowedActiveOwedMOf(address minter) external view returns (uint256);\n\n    /// @notice The inactive owed M of deactivated minter.\n    function inactiveOwedMOf(address minter) external view returns (uint240);\n\n    /// @notice The collateral of a given minter.\n    function collateralOf(address minter) external view returns (uint240);\n\n    /// @notice The timestamp of the last collateral update of minter.\n    function collateralUpdateTimestampOf(address minter) external view returns (uint40);\n\n    /// @notice The timestamp after which an additional penalty for a missed update interval will be charged.\n    function collateralPenaltyDeadlineOf(address minter) external view returns (uint40);\n\n    /// @notice The timestamp after which the minter's collateral is assumed to be 0 due to a missed update.\n    function collateralExpiryTimestampOf(address minter) external view returns (uint40);\n\n    /// @notice The timestamp until which minter is already penalized for missed collateral updates.\n    function penalizedUntilOf(address minter) external view returns (uint40);\n\n    /// @notice The timestamp when `minter` created their latest retrieval proposal.\n    function latestProposedRetrievalTimestampOf(address minter) external view returns (uint40);\n\n    /**\n     * @notice Returns the last signature timestamp used by `validator` to update collateral for `minter`.\n     * @param  minter    The address of the minter.\n     * @param  validator The address of the validator.\n     * @return The last signature timestamp used.\n     */\n    function getLastSignatureTimestamp(address minter, address validator) external view returns (uint256);\n\n    /**\n     * @notice Returns the EIP-712 digest for updateCollateral method.\n     * @param  minter       The address of the minter.\n     * @param  collateral   The amount of collateral.\n     * @param  retrievalIds The list of outstanding collateral retrieval IDs to resolve.\n     * @param  metadataHash The hash of metadata of the collateral update, reserved for future informational use.\n     * @param  timestamp    The timestamp of the collateral update.\n     */\n    function getUpdateCollateralDigest(\n        address minter,\n        uint256 collateral,\n        uint256[] calldata retrievalIds,\n        bytes32 metadataHash,\n        uint256 timestamp\n    ) external view returns (bytes32);\n\n    /// @notice The mint proposal of minters, only 1 active proposal per minter\n    function mintProposalOf(\n        address minter\n    ) external view returns (uint48 mintId, uint40 createdAt, address destination, uint240 amount);\n\n    /// @notice The amount of a pending retrieval request for an active minter.\n    function pendingCollateralRetrievalOf(address minter, uint256 retrievalId) external view returns (uint240);\n\n    /// @notice The total amount of pending retrieval requests for an active minter.\n    function totalPendingCollateralRetrievalOf(address minter) external view returns (uint240);\n\n    /// @notice The timestamp when minter becomes unfrozen after being frozen by validator.\n    function frozenUntilOf(address minter) external view returns (uint40);\n\n    /// @notice Checks if minter was activated after approval by TTG\n    function isActiveMinter(address minter) external view returns (bool);\n\n    /// @notice Checks if minter was deactivated after removal by TTG\n    function isDeactivatedMinter(address minter) external view returns (bool);\n\n    /// @notice Checks if minter was frozen by validator\n    function isFrozenMinter(address minter) external view returns (bool);\n\n    /// @notice Checks if minter was approved by TTG\n    function isMinterApproved(address minter) external view returns (bool);\n\n    /// @notice Checks if validator was approved by TTG\n    function isValidatorApproved(address validator) external view returns (bool);\n\n    /// @notice The delay between mint proposal creation and its earliest execution.\n    function mintDelay() external view returns (uint32);\n\n    /// @notice The time while mint request can still be processed before it is considered expired.\n    function mintTTL() external view returns (uint32);\n\n    /// @notice The freeze time for minter.\n    function minterFreezeTime() external view returns (uint32);\n\n    /// @notice The allowed activeOwedM to collateral ratio.\n    function mintRatio() external view returns (uint32);\n\n    /// @notice The % that defines penalty amount for missed collateral updates or excessive owedM value\n    function penaltyRate() external view returns (uint32);\n\n    /// @notice The smart contract that defines the minter rate.\n    function rateModel() external view returns (address);\n\n    /// @notice The interval that defines the required frequency of collateral updates.\n    function updateCollateralInterval() external view returns (uint32);\n\n    /// @notice The number of signatures required for successful collateral update.\n    function updateCollateralValidatorThreshold() external view returns (uint256);\n\n    /// @notice Descaler for variables in basis points. Effectively, 100% in basis points.\n    function ONE() external pure returns (uint16);\n\n    /// @notice Mint ratio cap. 650% in basis points.\n    function MAX_MINT_RATIO() external pure returns (uint32);\n\n    /// @notice Update collateral interval lower cap in seconds.\n    function MIN_UPDATE_COLLATERAL_INTERVAL() external pure returns (uint32);\n\n    /// @notice The EIP-712 typehash for the `updateCollateral` method.\n    function UPDATE_COLLATERAL_TYPEHASH() external pure returns (bytes32);\n}\n"},{"file_path":"lib/protocol/src/interfaces/IRateModel.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\n/**\n * @title  Rate Model Interface.\n * @author M^0 Labs\n */\ninterface IRateModel {\n    /**\n     * @notice Returns the current yearly rate in BPS.\n     *         This value does not account for the compounding interest.\n     */\n    function rate() external view returns (uint256);\n}\n"},{"file_path":"lib/protocol/src/interfaces/ITTGRegistrar.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\n/**\n * @title  TTG (Two Token Governance) Registrar interface.\n * @author M^0 Labs\n */\ninterface ITTGRegistrar {\n    /**\n     * @notice Key value pair getter.\n     * @param  key The key to get the value of.\n     * @return value The value of the key.\n     */\n    function get(bytes32 key) external view returns (bytes32 value);\n\n    /**\n     * @notice Checks if the list contains the account.\n     * @param  list The list to check.\n     * @param  account The account to check.\n     * @return True if the list contains the account, false otherwise.\n     */\n    function listContains(bytes32 list, address account) external view returns (bool);\n\n    /// @notice Returns the vault contract address.\n    function vault() external view returns (address);\n}\n"},{"file_path":"lib/protocol/src/libs/ContinuousIndexingMath.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { UIntMath } from \"../../lib/common/src/libs/UIntMath.sol\";\n\n/**\n * @title  Arithmetic library with operations for calculating continuous indexing.\n * @author M^0 Labs\n */\nlibrary ContinuousIndexingMath {\n    /* ============ Variables ============ */\n\n    /// @notice The number of seconds in a year.\n    uint32 internal constant SECONDS_PER_YEAR = 31_536_000;\n\n    /// @notice 100% in basis points.\n    uint16 internal constant BPS_SCALED_ONE = 1e4;\n\n    /// @notice The scaling of rates in for exponent math.\n    uint56 internal constant EXP_SCALED_ONE = 1e12;\n\n    /* ============ Custom Errors ============ */\n\n    /// @notice Emitted when a division by zero occurs.\n    error DivisionByZero();\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /**\n     * @notice Helper function to calculate `(x * EXP_SCALED_ONE) / index`, rounded down.\n     * @dev    Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\n     */\n    function divideDown(uint240 x, uint128 index) internal pure returns (uint112 z) {\n        if (index == 0) revert DivisionByZero();\n\n        unchecked {\n            // NOTE: While `uint256(x) * EXP_SCALED_ONE` can technically overflow, these divide/multiply functions are\n            //       only used for the purpose of principal/present amount calculations for continuous indexing, and\n            //       so for an `x` to be large enough to overflow this, it would have to be a possible result of\n            //       `multiplyDown` or `multiplyUp`, which would already satisfy\n            //       `uint256(x) * EXP_SCALED_ONE < type(uint240).max`.\n            return UIntMath.safe112((uint256(x) * EXP_SCALED_ONE) / index);\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate `(x * EXP_SCALED_ONE) / index`, rounded up.\n     * @dev    Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\n     */\n    function divideUp(uint240 x, uint128 index) internal pure returns (uint112 z) {\n        if (index == 0) revert DivisionByZero();\n\n        unchecked {\n            // NOTE: While `uint256(x) * EXP_SCALED_ONE` can technically overflow, these divide/multiply functions are\n            //       only used for the purpose of principal/present amount calculations for continuous indexing, and\n            //       so for an `x` to be large enough to overflow this, it would have to be a possible result of\n            //       `multiplyDown` or `multiplyUp`, which would already satisfy\n            //       `uint256(x) * EXP_SCALED_ONE < type(uint240).max`.\n            return UIntMath.safe112(((uint256(x) * EXP_SCALED_ONE) + index - 1) / index);\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate `(x * index) / EXP_SCALED_ONE`, rounded down.\n     * @dev    Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\n     */\n    function multiplyDown(uint112 x, uint128 index) internal pure returns (uint240 z) {\n        unchecked {\n            return uint240((uint256(x) * index) / EXP_SCALED_ONE);\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate `(x * index) / EXP_SCALED_ONE`, rounded up.\n     * @dev    Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\n     */\n    function multiplyUp(uint112 x, uint128 index) internal pure returns (uint240 z) {\n        unchecked {\n            return uint240(((uint256(x) * index) + (EXP_SCALED_ONE - 1)) / EXP_SCALED_ONE);\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate `(index * deltaIndex) / EXP_SCALED_ONE`, rounded down.\n     * @dev    Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\n     */\n    function multiplyIndicesDown(uint128 index, uint48 deltaIndex) internal pure returns (uint144 z) {\n        unchecked {\n            return uint144((uint256(index) * deltaIndex) / EXP_SCALED_ONE);\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate `(index * deltaIndex) / EXP_SCALED_ONE`, rounded up.\n     * @dev    Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)\n     */\n    function multiplyIndicesUp(uint128 index, uint48 deltaIndex) internal pure returns (uint144 z) {\n        unchecked {\n            return uint144((uint256(index) * deltaIndex + (EXP_SCALED_ONE - 1)) / EXP_SCALED_ONE);\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate e^rt (continuous compounding formula).\n     * @dev    `uint64 yearlyRate` can accommodate 1000% interest per year.\n     * @dev    `uint32 time` can accommodate 100 years.\n     * @dev    `type(uint64).max * type(uint32).max / SECONDS_PER_YEAR` fits in a `uint72`.\n     */\n    function getContinuousIndex(uint64 yearlyRate, uint32 time) internal pure returns (uint48 index) {\n        unchecked {\n            // NOTE: Casting `uint256(yearlyRate) * time` to a `uint72` is safe because the largest value is\n            //      `type(uint64).max * type(uint32).max / SECONDS_PER_YEAR`, which is less than `type(uint72).max`.\n            return exponent(uint72((uint256(yearlyRate) * time) / SECONDS_PER_YEAR));\n        }\n    }\n\n    /**\n     * @notice Helper function to calculate y = e^x using R(4,4) Padé approximation:\n     *           e(x) = (1 + x/2 + 3(x^2)/28 + x^3/84 + x^4/1680) / (1 - x/2 + 3(x^2)/28 - x^3/84 + x^4/1680)\n     *           See: https://en.wikipedia.org/wiki/Pad%C3%A9_table\n     *           See: https://www.wolframalpha.com/input?i=PadeApproximant%5Bexp%5Bx%5D%2C%7Bx%2C0%2C%7B4%2C+4%7D%7D%5D\n     *         Despite itself being a whole number, `x` represents a real number scaled by `EXP_SCALED_ONE`, thus\n     *         allowing for y = e^x where x is a real number.\n     * @dev    Output `y` for a `uint72` input `x` will fit in `uint48`\n     */\n    function exponent(uint72 x) internal pure returns (uint48 y) {\n        // NOTE: This can be done unchecked even for `x = type(uint72).max`.\n        //       Verify by removing `unchecked` and running `test_exponent()`.\n        unchecked {\n            uint256 x2 = uint256(x) * x;\n\n            // `additiveTerms` is `(1 + 3(x^2)/28 + x^4/1680)`, and scaled by `84e27`.\n            // NOTE: `84e27` the cleanest and largest scalar, given the various intermediate overflow possibilities.\n            // NOTE: The resulting `(x2 * x2) / 20e21` term has been split up in order to avoid overflow of `x2 * x2`.\n            uint256 additiveTerms = 84e27 + (9e3 * x2) + ((x2 / 2e11) * (x2 / 1e11));\n\n            // `differentTerms` is `(- x/2 - x^3/84)`, but positive (will be subtracted later), and scaled by `84e27`.\n            uint256 differentTerms = uint256(x) * (42e15 + (x2 / 1e9));\n\n            // Result needs to be scaled by `1e12`.\n            // NOTE: Can cast to `uint48` because contents can never be larger than `type(uint48).max` for any `x`.\n            //       Max `y` is ~200e12, before falling off. See links above for reference.\n            return uint48(((additiveTerms + differentTerms) * 1e12) / (additiveTerms - differentTerms));\n        }\n    }\n\n    /**\n     * @notice Helper function to convert 12-decimal representation to basis points.\n     * @param  input The input in 12-decimal representation.\n     * @return The output in basis points.\n     */\n    function convertToBasisPoints(uint64 input) internal pure returns (uint40) {\n        unchecked {\n            return uint40((uint256(input) * BPS_SCALED_ONE) / EXP_SCALED_ONE);\n        }\n    }\n\n    /**\n     * @notice Helper function to convert basis points to 12-decimal representation.\n     * @param  input The input in basis points.\n     * @return The output in 12-decimal representation.\n     */\n    function convertFromBasisPoints(uint32 input) internal pure returns (uint64) {\n        unchecked {\n            return uint64((uint256(input) * EXP_SCALED_ONE) / BPS_SCALED_ONE);\n        }\n    }\n}\n"},{"file_path":"lib/protocol/src/libs/TTGRegistrarReader.sol","source_code":"// SPDX-License-Identifier: GPL-3.0\n\npragma solidity 0.8.23;\n\nimport { ITTGRegistrar } from \"../interfaces/ITTGRegistrar.sol\";\n\n/**\n * @title  Library to read TTG (Two Token Governance) Registrar contract parameters.\n * @author M^0 Labs\n */\nlibrary TTGRegistrarReader {\n    /* ============ Variables ============ */\n\n    /// @notice The name of parameter in TTG that defines the earner rate model contract.\n    bytes32 internal constant EARNER_RATE_MODEL = \"earner_rate_model\";\n\n    /// @notice The parameter name in TTG that defines the earners list.\n    bytes32 internal constant EARNERS_LIST = \"earners\";\n\n    /// @notice The parameter name in TTG that defines whether to ignore the earners list or not.\n    bytes32 internal constant EARNERS_LIST_IGNORED = \"earners_list_ignored\";\n\n    /// @notice The parameter name in TTG that defines the time to wait for mint request to be processed.\n    bytes32 internal constant MINT_DELAY = \"mint_delay\";\n\n    /// @notice The parameter name in TTG that defines the mint ratio.\n    bytes32 internal constant MINT_RATIO = \"mint_ratio\"; // bps\n\n    /// @notice The parameter name in TTG that defines the time while mint request can still be processed.\n    bytes32 internal constant MINT_TTL = \"mint_ttl\";\n\n    /// @notice The parameter name in TTG that defines the time to freeze minter.\n    bytes32 internal constant MINTER_FREEZE_TIME = \"minter_freeze_time\";\n\n    /// @notice The parameter name in TTG that defines the minter rate model contract.\n    bytes32 internal constant MINTER_RATE_MODEL = \"minter_rate_model\";\n\n    /// @notice The parameter name in TTG that defines the minters list.\n    bytes32 internal constant MINTERS_LIST = \"minters\";\n\n    /// @notice The parameter name in TTG that defines the penalty rate.\n    bytes32 internal constant PENALTY_RATE = \"penalty_rate\"; // bps\n\n    /// @notice The parameter name in TTG that defines the required interval to update collateral.\n    bytes32 internal constant UPDATE_COLLATERAL_INTERVAL = \"update_collateral_interval\";\n\n    /// @notice The parameter name that defines number of signatures required for successful collateral update.\n    bytes32 internal constant UPDATE_COLLATERAL_VALIDATOR_THRESHOLD = \"update_collateral_threshold\";\n\n    /// @notice The parameter name in TTG that defines the validators list.\n    bytes32 internal constant VALIDATORS_LIST = \"validators\";\n\n    /* ============ Internal View/Pure Functions ============ */\n\n    /// @notice Gets the earner rate model contract address.\n    function getEarnerRateModel(address registrar_) internal view returns (address) {\n        return toAddress(_get(registrar_, EARNER_RATE_MODEL));\n    }\n\n    /// @notice Gets the mint delay.\n    function getMintDelay(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, MINT_DELAY));\n    }\n\n    /// @notice Gets the minter freeze time.\n    function getMinterFreezeTime(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, MINTER_FREEZE_TIME));\n    }\n\n    /// @notice Gets the minter rate model contract address.\n    function getMinterRateModel(address registrar_) internal view returns (address) {\n        return toAddress(_get(registrar_, MINTER_RATE_MODEL));\n    }\n\n    /// @notice Gets the mint TTL.\n    function getMintTTL(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, MINT_TTL));\n    }\n\n    /// @notice Gets the mint ratio.\n    function getMintRatio(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, MINT_RATIO));\n    }\n\n    /// @notice Gets the update collateral interval.\n    function getUpdateCollateralInterval(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, UPDATE_COLLATERAL_INTERVAL));\n    }\n\n    /// @notice Gets the update collateral validator threshold.\n    function getUpdateCollateralValidatorThreshold(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, UPDATE_COLLATERAL_VALIDATOR_THRESHOLD));\n    }\n\n    /// @notice Checks if the given earner is approved.\n    function isApprovedEarner(address registrar_, address earner_) internal view returns (bool) {\n        return _contains(registrar_, EARNERS_LIST, earner_);\n    }\n\n    /// @notice Checks if the `earners_list_ignored` exists.\n    function isEarnersListIgnored(address registrar_) internal view returns (bool) {\n        return _get(registrar_, EARNERS_LIST_IGNORED) != bytes32(0);\n    }\n\n    /// @notice Checks if the given minter is approved.\n    function isApprovedMinter(address registrar_, address minter_) internal view returns (bool) {\n        return _contains(registrar_, MINTERS_LIST, minter_);\n    }\n\n    /// @notice Checks if the given validator is approved.\n    function isApprovedValidator(address registrar_, address validator_) internal view returns (bool) {\n        return _contains(registrar_, VALIDATORS_LIST, validator_);\n    }\n\n    /// @notice Gets the penalty rate.\n    function getPenaltyRate(address registrar_) internal view returns (uint256) {\n        return uint256(_get(registrar_, PENALTY_RATE));\n    }\n\n    /// @notice Gets the vault contract address.\n    function getVault(address registrar_) internal view returns (address) {\n        return ITTGRegistrar(registrar_).vault();\n    }\n\n    /// @notice Converts given bytes32 to address.\n    function toAddress(bytes32 input_) internal pure returns (address) {\n        return address(uint160(uint256(input_)));\n    }\n\n    /// @notice Checks if the given list contains the given account.\n    function _contains(address registrar_, bytes32 listName_, address account_) private view returns (bool) {\n        return ITTGRegistrar(registrar_).listContains(listName_, account_);\n    }\n\n    /// @notice Gets the value of the given key.\n    function _get(address registrar_, bytes32 key_) private view returns (bytes32) {\n        return ITTGRegistrar(registrar_).get(key_);\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"ttgRegistrar_","type":"address"},{"internalType":"address","name":"mToken_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeactivatedMinter","type":"error"},{"inputs":[],"name":"DivisionByZero","type":"error"},{"inputs":[{"internalType":"uint240","name":"amount","type":"uint240"},{"internalType":"uint240","name":"maxAmount","type":"uint240"}],"name":"ExceedsMaxRepayAmount","type":"error"},{"inputs":[{"internalType":"uint40","name":"deadline","type":"uint40"}],"name":"ExpiredMintProposal","type":"error"},{"inputs":[],"name":"FrozenMinter","type":"error"},{"inputs":[],"name":"FutureTimestamp","type":"error"},{"inputs":[],"name":"InactiveMinter","type":"error"},{"inputs":[],"name":"InvalidMintProposal","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidSignatureLength","type":"error"},{"inputs":[],"name":"InvalidSignatureOrder","type":"error"},{"inputs":[],"name":"InvalidSignatureS","type":"error"},{"inputs":[],"name":"InvalidSignatureV","type":"error"},{"inputs":[],"name":"InvalidUInt112","type":"error"},{"inputs":[],"name":"InvalidUInt240","type":"error"},{"inputs":[],"name":"InvalidUInt48","type":"error"},{"inputs":[],"name":"NotApprovedMinter","type":"error"},{"inputs":[{"internalType":"address","name":"validator","type":"address"}],"name":"NotApprovedValidator","type":"error"},{"inputs":[{"internalType":"uint256","name":"validSignatures","type":"uint256"},{"internalType":"uint256","name":"requiredThreshold","type":"uint256"}],"name":"NotEnoughValidSignatures","type":"error"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"lastSignatureTimestamp","type":"uint256"}],"name":"OutdatedValidatorTimestamp","type":"error"},{"inputs":[],"name":"OverflowsPrincipalOfTotalOwedM","type":"error"},{"inputs":[{"internalType":"uint40","name":"activeTimestamp","type":"uint40"}],"name":"PendingMintProposal","type":"error"},{"inputs":[{"internalType":"uint240","name":"totalPendingRetrievals","type":"uint240"},{"internalType":"uint240","name":"collateral","type":"uint240"}],"name":"RetrievalsExceedCollateral","type":"error"},{"inputs":[],"name":"SignatureArrayLengthsMismatch","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":[{"internalType":"uint40","name":"newTimestamp","type":"uint40"},{"internalType":"uint40","name":"earliestAllowedTimestamp","type":"uint40"}],"name":"StaleCollateralUpdate","type":"error"},{"inputs":[],"name":"StillApprovedMinter","type":"error"},{"inputs":[{"internalType":"uint256","name":"activeOwedM","type":"uint256"},{"internalType":"uint256","name":"maxAllowedOwedM","type":"uint256"}],"name":"Undercollateralized","type":"error"},{"inputs":[],"name":"ZeroBurnAmount","type":"error"},{"inputs":[],"name":"ZeroMToken","type":"error"},{"inputs":[],"name":"ZeroMintAmount","type":"error"},{"inputs":[],"name":"ZeroMintDestination","type":"error"},{"inputs":[],"name":"ZeroRetrievalAmount","type":"error"},{"inputs":[],"name":"ZeroTTGRegistrar","type":"error"},{"inputs":[],"name":"ZeroTTGVault","type":"error"},{"inputs":[],"name":"ZeroTimestamp","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint240","name":"amount","type":"uint240"},{"indexed":true,"internalType":"address","name":"payer","type":"address"}],"name":"BurnExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint112","name":"principalAmount","type":"uint112"},{"indexed":false,"internalType":"uint240","name":"amount","type":"uint240"},{"indexed":true,"internalType":"address","name":"payer","type":"address"}],"name":"BurnExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint240","name":"collateral","type":"uint240"},{"indexed":false,"internalType":"uint240","name":"totalResolvedCollateralRetrieval","type":"uint240"},{"indexed":true,"internalType":"bytes32","name":"metadataHash","type":"bytes32"},{"indexed":false,"internalType":"uint40","name":"timestamp","type":"uint40"}],"name":"CollateralUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint128","name":"index","type":"uint128"},{"indexed":true,"internalType":"uint32","name":"rate","type":"uint32"}],"name":"IndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"mintId","type":"uint48"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"canceller","type":"address"}],"name":"MintCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"mintId","type":"uint48"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint112","name":"principalAmount","type":"uint112"},{"indexed":false,"internalType":"uint240","name":"amount","type":"uint240"}],"name":"MintExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"mintId","type":"uint48"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint240","name":"amount","type":"uint240"},{"indexed":true,"internalType":"address","name":"destination","type":"address"}],"name":"MintProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"MinterActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint240","name":"inactiveOwedM","type":"uint240"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"MinterDeactivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint40","name":"frozenUntil","type":"uint40"}],"name":"MinterFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint40","name":"missedIntervals","type":"uint40"},{"indexed":false,"internalType":"uint240","name":"penaltyAmount","type":"uint240"}],"name":"MissedIntervalsPenaltyImposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"retrievalId","type":"uint48"},{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint240","name":"amount","type":"uint240"}],"name":"RetrievalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint48","name":"retrievalId","type":"uint48"},{"indexed":true,"internalType":"address","name":"minter","type":"address"}],"name":"RetrievalResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint240","name":"excessOwedM","type":"uint240"},{"indexed":false,"internalType":"uint40","name":"timeSpan","type":"uint40"},{"indexed":false,"internalType":"uint240","name":"penaltyAmount","type":"uint240"}],"name":"UndercollateralizedPenaltyImposed","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_MINT_RATIO","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_UPDATE_COLLATERAL_INTERVAL","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPDATE_COLLATERAL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"activateMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"activeOwedMOf","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"},{"internalType":"uint256","name":"maxPrincipalAmount_","type":"uint256"},{"internalType":"uint256","name":"maxAmount_","type":"uint256"}],"name":"burnM","outputs":[{"internalType":"uint112","name":"principalAmount_","type":"uint112"},{"internalType":"uint240","name":"amount_","type":"uint240"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"},{"internalType":"uint256","name":"maxAmount_","type":"uint256"}],"name":"burnM","outputs":[{"internalType":"uint112","name":"principalAmount_","type":"uint112"},{"internalType":"uint240","name":"amount_","type":"uint240"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"},{"internalType":"uint256","name":"mintId_","type":"uint256"}],"name":"cancelMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"collateralExpiryTimestampOf","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"collateralOf","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"collateralPenaltyDeadlineOf","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"collateralUpdateTimestampOf","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentIndex","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"deactivateMinter","outputs":[{"internalType":"uint240","name":"inactiveOwedM_","type":"uint240"}],"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":"excessOwedM","outputs":[{"internalType":"uint240","name":"excessOwedM_","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"freezeMinter","outputs":[{"internalType":"uint40","name":"frozenUntil_","type":"uint40"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"frozenUntilOf","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"},{"internalType":"address","name":"validator_","type":"address"}],"name":"getLastSignatureTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"},{"internalType":"uint256","name":"collateral_","type":"uint256"},{"internalType":"uint256[]","name":"retrievalIds_","type":"uint256[]"},{"internalType":"bytes32","name":"metadataHash_","type":"bytes32"},{"internalType":"uint256","name":"timestamp_","type":"uint256"}],"name":"getUpdateCollateralDigest","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"inactiveOwedMOf","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"isActiveMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"isDeactivatedMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"isFrozenMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"isMinterApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"validator_","type":"address"}],"name":"isValidatorApproved","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestIndex","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"latestProposedRetrievalTimestampOf","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestUpdateTimestamp","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"maxAllowedActiveOwedMOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintDelay","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintId_","type":"uint256"}],"name":"mintM","outputs":[{"internalType":"uint112","name":"principalAmount_","type":"uint112"},{"internalType":"uint240","name":"amount_","type":"uint240"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"mintProposalOf","outputs":[{"internalType":"uint48","name":"mintId_","type":"uint48"},{"internalType":"uint40","name":"createdAt_","type":"uint40"},{"internalType":"address","name":"destination_","type":"address"},{"internalType":"uint240","name":"amount_","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintRatio","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintTTL","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterFreezeTime","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minterRate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"penalizedUntilOf","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"penaltyRate","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"},{"internalType":"uint256","name":"retrievalId_","type":"uint256"}],"name":"pendingCollateralRetrievalOf","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"principalOfActiveOwedMOf","outputs":[{"internalType":"uint112","name":"","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"principalOfTotalActiveOwedM","outputs":[{"internalType":"uint112","name":"","type":"uint112"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"address","name":"destination_","type":"address"}],"name":"proposeMint","outputs":[{"internalType":"uint48","name":"mintId_","type":"uint48"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateral_","type":"uint256"}],"name":"proposeRetrieval","outputs":[{"internalType":"uint48","name":"retrievalId_","type":"uint48"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rateModel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalActiveOwedM","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalInactiveOwedM","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalOwedM","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"minter_","type":"address"}],"name":"totalPendingCollateralRetrievalOf","outputs":[{"internalType":"uint240","name":"","type":"uint240"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttgRegistrar","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ttgVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"collateral_","type":"uint256"},{"internalType":"uint256[]","name":"retrievalIds_","type":"uint256[]"},{"internalType":"bytes32","name":"metadataHash_","type":"bytes32"},{"internalType":"address[]","name":"validators_","type":"address[]"},{"internalType":"uint256[]","name":"timestamps_","type":"uint256[]"},{"internalType":"bytes[]","name":"signatures_","type":"bytes[]"}],"name":"updateCollateral","outputs":[{"internalType":"uint40","name":"minTimestamp_","type":"uint40"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateCollateralInterval","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateCollateralValidatorThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateIndex","outputs":[{"internalType":"uint128","name":"index_","type":"uint128"}],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"000000000000000000000000119fbeedd4f4f4298fb59b720d5654442b81ae2c000000000000000000000000866a2bf4e572cbcf37d5071a7a58503bfb36be1b"}