{"file_path":"src/MetaOracleDeviationTimelock.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport {Initializable} from \"@openzeppelin/contracts/proxy/utils/Initializable.sol\";\nimport {IMetaOracleDeviationTimelock} from \"./interfaces/IMetaOracleDeviationTimelock.sol\";\nimport {IOracle} from \"./interfaces/IOracle.sol\";\n\n/// @title MetaOracleDeviationTimelock\n/// @author Steakhouse Financial\n/// @notice A meta-oracle that selects between a primary and backup oracle based on price deviation and timelocks.\n/// @dev Switches to backup if primary deviates significantly, switches back when prices reconverge.\n/// MUST be initialized by calling the `initialize` function.\ncontract MetaOracleDeviationTimelock is IMetaOracleDeviationTimelock, Initializable {\n    // --- Configuration (set during initialization) ---\n    IOracle public primaryOracle;\n    IOracle public backupOracle;\n    uint256 public deviationThreshold; // Scaled by 1e18 (e.g., 0.01e18 for 1%)\n    uint256 public challengeTimelockDuration; // Duration in seconds\n    uint256 public healingTimelockDuration; // Duration in seconds\n\n    // --- State ---\n    IOracle public currentOracle; // Currently selected oracle\n    uint256 public challengeExpiresAt; // Timestamp when challenge period ends (0 if not challenged)\n    uint256 public healingExpiresAt; // Timestamp when healing period ends (0 if not healing)\n\n    /// @param _primaryOracle The primary price feed.\n    /// @param _backupOracle The backup price feed.\n    /// @param _deviationThreshold The maximum allowed relative deviation (scaled by 1e18) before a challenge can be initiated.\n    /// @param _challengeTimelockDuration The duration (seconds) a challenge must persist before switching to backup.\n    /// @param _healingTimelockDuration The duration (seconds) prices must remain converged before switching back to primary.\n    function initialize(\n        IOracle _primaryOracle,\n        IOracle _backupOracle,\n        uint256 _deviationThreshold,\n        uint256 _challengeTimelockDuration,\n        uint256 _healingTimelockDuration\n    ) external initializer {\n        require(address(_primaryOracle) != address(0), \"Invalid primary oracle\");\n        require(address(_backupOracle) != address(0), \"Invalid backup oracle\");\n        require(address(_primaryOracle) != address(_backupOracle), \"Oracles must be different\");\n        require(_deviationThreshold > 0, \"Deviation threshold must be positive\");\n\n        primaryOracle = _primaryOracle;\n        backupOracle = _backupOracle;\n        deviationThreshold = _deviationThreshold;\n        challengeTimelockDuration = _challengeTimelockDuration;\n        healingTimelockDuration = _healingTimelockDuration;\n\n        // Check initial deviation\n        uint256 initialPrimaryPrice = _primaryOracle.price();\n        uint256 initialBackupPrice = _backupOracle.price();\n        uint256 initialDeviation;\n        if (initialBackupPrice == 0) {\n            initialDeviation = initialPrimaryPrice == 0 ? 0 : type(uint256).max;\n        } else {\n            uint256 diff;\n            if (initialPrimaryPrice >= initialBackupPrice) {\n                diff = initialPrimaryPrice - initialBackupPrice;\n            } else {\n                diff = initialBackupPrice - initialPrimaryPrice;\n            }\n            initialDeviation = (diff * 10**18) / initialBackupPrice;\n        }\n        require(initialDeviation <= _deviationThreshold, \"MODT: Initial deviation too high\");\n\n        currentOracle = _primaryOracle; // Start with the primary oracle\n    }\n\n    /// @inheritdoc IOracle\n    function price() public view returns (uint256) {\n        try currentOracle.price() returns (uint256 currentPrice) {\n            return currentPrice;\n        } catch {\n            if (isPrimary()) {\n                return backupOracle.price();\n            } else {\n                return primaryOracle.price();\n            }\n        }\n    }\n\n    /// @inheritdoc IMetaOracleDeviationTimelock\n    function primaryPrice() public view returns (uint256) {\n        return primaryOracle.price();\n    }\n\n    /// @inheritdoc IMetaOracleDeviationTimelock\n    function backupPrice() public view returns (uint256) {\n        return backupOracle.price();\n    }\n\n    /// @notice Checks if the primary oracle is currently selected.\n    function isPrimary() public view returns (bool) {\n        return currentOracle == primaryOracle;\n    }\n\n    /// @notice Checks if the backup oracle is currently selected.\n    function isBackup() public view returns (bool) {\n        return currentOracle == backupOracle;\n    }\n\n    /// @notice Checks if a challenge is currently active.\n    function isChallenged() public view returns (bool) {\n        return challengeExpiresAt > 0;\n    }\n\n    /// @notice Checks if a healing period is currently active.\n    function isHealing() public view returns (bool) {\n        return healingExpiresAt > 0;\n    }\n\n    /// @notice Calculates the absolute relative deviation between primary and backup oracles.\n    /// @dev Deviation is calculated as `abs(primaryPrice - backupPrice) * 1e18 / backupPrice`.\n    /// Returns 0 if backupPrice is 0 and primaryPrice is 0.\n    /// Returns type(uint256).max if backupPrice is 0 and primaryPrice is non-zero.\n    function getDeviation() public view returns (uint256) {\n        uint256 currentPrimaryPrice = primaryOracle.price();\n        uint256 currentBackupPrice = backupOracle.price();\n\n        if (currentBackupPrice == 0) {\n            return currentPrimaryPrice == 0 ? 0 : type(uint256).max;\n        }\n\n        uint256 diff;\n        if (currentPrimaryPrice >= currentBackupPrice) {\n            diff = currentPrimaryPrice - currentBackupPrice;\n        } else {\n            diff = currentBackupPrice - currentPrimaryPrice;\n        }\n\n        // Use uint256 for intermediate multiplication to avoid overflow before division\n        return (diff * 10**18) / currentBackupPrice;\n    }\n\n    /// @notice Checks if the deviation exceeds the configured threshold.\n    function isDeviant() public view returns (bool) {\n        return getDeviation() > deviationThreshold;\n    }\n\n    /// @notice Initiates a challenge if the primary oracle is active and deviation threshold is exceeded.\n    /// @dev Starts a timelock period (`challengeTimelockDuration`).\n    function challenge() external {\n        require(isPrimary(), \"MODT: Must be primary oracle\");\n        require(!isChallenged(), \"MODT: Already challenged\");\n        require(isDeviant(), \"MODT: Deviation threshold not met\");\n\n        challengeExpiresAt = block.timestamp + challengeTimelockDuration;\n        emit ChallengeStarted(challengeExpiresAt);\n    }\n\n    /// @notice Revokes an active challenge if the deviation is no longer present.\n    function revokeChallenge() external {\n        require(isPrimary(), \"MODT: Must be primary oracle\"); // Should still be primary\n        require(isChallenged(), \"MODT: Not challenged\");\n        require(!isDeviant(), \"MODT: Deviation threshold still met\");\n\n        challengeExpiresAt = 0;\n        emit ChallengeRevoked();\n    }\n\n    /// @notice Checks if the challenge has expired.\n    function hasChallengeExpired() public view returns (bool) {\n        return isChallenged() && block.timestamp >= challengeExpiresAt;\n    }\n\n    /// @notice Checks if the challenge can be accepted.\n    function canAcceptChallenge() public view returns (bool) {\n        return isPrimary() && isChallenged() && block.timestamp >= challengeExpiresAt && isDeviant();\n    }\n\n    /// @notice Accepts the challenge after the timelock expires, switching to the backup oracle.\n    /// @dev Requires the deviation to still be present.\n    function acceptChallenge() external {\n        require(isPrimary(), \"MODT: Must be primary oracle\");\n        require(isChallenged(), \"MODT: Not challenged\");\n        require(block.timestamp >= challengeExpiresAt, \"MODT: Challenge timelock not passed\");\n        require(isDeviant(), \"MODT: Deviation resolved\"); // Deviation must persist\n\n        currentOracle = backupOracle;\n        challengeExpiresAt = 0;\n        emit ChallengeAccepted(address(currentOracle));\n    }\n\n    /// @notice Initiates the healing process if the backup oracle is active and prices have reconverged.\n    /// @dev Starts a timelock period (`healingTimelockDuration`).\n    function heal() external {\n        require(isBackup(), \"MODT: Must be backup oracle\");\n        require(!isHealing(), \"MODT: Already healing\");\n        require(!isDeviant(), \"MODT: Deviation threshold still met\");\n\n        healingExpiresAt = block.timestamp + healingTimelockDuration;\n        emit HealingStarted(healingExpiresAt);\n    }\n\n    /// @notice Revokes an active healing process if the deviation threshold is exceeded again.\n    function revokeHealing() external {\n        require(isBackup(), \"MODT: Must be backup oracle\"); // Should still be backup\n        require(isHealing(), \"MODT: Not healing\");\n        require(isDeviant(), \"MODT: Deviation threshold not met\");\n\n        healingExpiresAt = 0;\n        emit HealingRevoked();\n    }\n\n    /// @notice Checks if the healing has expired.\n    function hasHealingExpired() public view returns (bool) {\n        return isHealing() && block.timestamp >= healingExpiresAt;\n    }\n\n    /// @notice Checks if the healing can be accepted.\n    function canAcceptHealing() public view returns (bool) {\n        return isBackup() && isHealing() && block.timestamp >= healingExpiresAt && !isDeviant();\n    }\n\n    /// @notice Accepts the healing after the timelock expires, switching back to the primary oracle.\n    /// @dev Requires the prices to still be converged (not deviant).\n    function acceptHealing() external {\n        require(isBackup(), \"MODT: Must be backup oracle\");\n        require(isHealing(), \"MODT: Not healing\");\n        require(block.timestamp >= healingExpiresAt, \"MODT: Healing timelock not passed\");\n        require(!isDeviant(), \"MODT: Deviation occurred\"); // Prices must remain converged\n\n        currentOracle = primaryOracle;\n        healingExpiresAt = 0;\n        emit HealingAccepted(address(currentOracle));\n    }\n}","deployed_bytecode":"0x608060405234801561000f575f5ffd5b50600436106101c1575f3560e01c8063a035b1fe116100f7578063d2ef739811610095578063de1a69751161006f578063de1a69751461042f578063e2997d6b1461044d578063f8f8b5f014610457578063f9e3444714610475576101c1565b8063d2ef7398146103e9578063d83ed440146103f3578063d94ad83714610411576101c1565b8063bd8f238e116100d1578063bd8f238e14610373578063c2ee5df914610391578063ccc1b9cd146103af578063d13f90b4146103cd576101c1565b8063a035b1fe1461032d578063ad8910061461034b578063b166bf6b14610369576101c1565b8063362a07ae116101645780637ad6d6d51161013e5780637ad6d6d5146102b5578063836efd31146102d357806389ab3532146102f15780639df4d0fe1461030f576101c1565b8063362a07ae1461025b5780633682152b14610279578063498e8b6e14610297576101c1565b80631fc08644116101a05780631fc08644146101f7578063219a94b8146102155780632289445e1461021f5780632f0a577b1461023d576101c1565b8062372f87146101c557806303c01e68146101cf5780630434fe0b146101ed575b5f5ffd5b6101cd610493565b005b6101d761059d565b6040516101e4919061199e565b60405180910390f35b6101f5610614565b005b6101ff61073a565b60405161020c919061199e565b60405180910390f35b61021d610776565b005b61022761095e565b6040516102349190611a31565b60405180910390f35b610245610983565b604051610252919061199e565b60405180910390f35b61026361099f565b6040516102709190611a62565b60405180910390f35b610281610a32565b60405161028e919061199e565b60405180910390f35b61029f610aa8565b6040516102ac9190611a62565b60405180910390f35b6102bd610aae565b6040516102ca919061199e565b60405180910390f35b6102db610aeb565b6040516102e89190611a31565b60405180910390f35b6102f9610b10565b6040516103069190611a62565b60405180910390f35b610317610cc3565b604051610324919061199e565b60405180910390f35b610335610cce565b6040516103429190611a62565b60405180910390f35b610353610e9a565b6040516103609190611a62565b60405180910390f35b610371610f2e565b005b61037b611116565b6040516103889190611a31565b60405180910390f35b61039961113a565b6040516103a6919061199e565b60405180910390f35b6103b7611156565b6040516103c49190611a62565b60405180910390f35b6103e760048036038101906103e29190611af5565b61115c565b005b6103f16116e9565b005b6103fb61180e565b6040516104089190611a62565b60405180910390f35b610419611814565b6040516104269190611a62565b60405180910390f35b61043761181a565b604051610444919061199e565b60405180910390f35b61045561182c565b005b61045f611937565b60405161046c919061199e565b60405180910390f35b61047d611942565b60405161048a9190611a62565b60405180910390f35b61049b61059d565b6104da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d190611bc6565b60405180910390fd5b6104e2611937565b610521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161051890611c2e565b60405180910390fd5b61052961181a565b610568576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161055f90611cbc565b60405180910390fd5b5f6007819055507ff5decdb337f3f69eb4a1610788fd6d8325897945c0f070fef7218c25b84ea90860405160405180910390a1565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b61061c61059d565b61065b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065290611bc6565b60405180910390fd5b610663611937565b156106a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161069a90611d24565b60405180910390fd5b6106ab61181a565b156106eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e290611db2565b60405180910390fd5b600454426106f99190611dfd565b6007819055507fb36d2484c6d35cccf36d46eafe82aa81628f80b9c4e6d1828f5837236a0641bd6007546040516107309190611a62565b60405180910390a1565b5f610743610a32565b80156107535750610752610cc3565b5b801561076157506006544210155b8015610771575061077061181a565b5b905090565b61077e61059d565b6107bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b490611bc6565b60405180910390fd5b6107c5611937565b610804576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107fb90611c2e565b60405180910390fd5b600754421015610849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084090611ea0565b60405180910390fd5b61085161181a565b15610891576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088890611f08565b60405180910390fd5b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60078190555060055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f184591035d84fab784c414962589ca8bf109c62ce76e7b318ca83c16c7c63b6460405160405180910390a2565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f61098c610cc3565b801561099a57506006544210155b905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2d9190611f3a565b905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b60035481565b5f610ab761059d565b8015610ac75750610ac6611937565b5b8015610ad557506007544210155b8015610ae65750610ae461181a565b155b905090565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b7b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9f9190611f3a565b90505f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c309190611f3a565b90505f8103610c71575f8214610c66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610c68565b5f5b92505050610cc0565b5f818310610c8c578183610c859190611f65565b9050610c9b565b8282610c989190611f65565b90505b81670de0b6b3a764000082610cb09190611f98565b610cba9190612006565b93505050505b90565b5f5f60065411905090565b5f60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610d5857506040513d601f19601f82011682018060405250810190610d559190611f3a565b60015b610e9257610d64610a32565b15610dfe5760015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dd3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610df79190611f3a565b9050610e97565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e67573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8b9190611f3a565b9050610e97565b809150505b90565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f05573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f299190611f3a565b905090565b610f36610a32565b610f75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f6c90612080565b60405180910390fd5b610f7d610cc3565b610fbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb3906120e8565b60405180910390fd5b600654421015611001576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ff890612176565b60405180910390fd5b61100961181a565b611048576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161103f906121de565b60405180910390fd5b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60068190555060055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f235d3c92abef402ad8969f43056a1212760efee2e4357b1e165a93aed19329e360405160405180910390a2565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f611143611937565b801561115157506007544210155b905090565b60065481565b5f611165611948565b90505f815f0160089054906101000a900460ff161590505f825f015f9054906101000a900467ffffffffffffffff1690505f5f8267ffffffffffffffff161480156111ad5750825b90505f60018367ffffffffffffffff161480156111e057505f3073ffffffffffffffffffffffffffffffffffffffff163b145b9050811580156111ee575080155b15611225576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001855f015f6101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508315611272576001855f0160086101000a81548160ff0219169083151502179055505b5f73ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16036112e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d790612246565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff160361134e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611345906122ae565b60405180910390fd5b8873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16036113bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113b390612316565b60405180910390fd5b5f88116113fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f5906123a4565b60405180910390fd5b895f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508860015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508760028190555086600381905550856004819055505f8a73ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114dc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115009190611f3a565b90505f8a73ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561154c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115709190611f3a565b90505f5f82036115b0575f83146115a7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6115a9565b5f5b90506115fd565b5f8284106115cb5782846115c49190611f65565b90506115da565b83836115d79190611f65565b90505b82670de0b6b3a7640000826115ef9190611f98565b6115f99190612006565b9150505b8a811115611640576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116379061240c565b60405180910390fd5b8c60055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505083156116dd575f855f0160086101000a81548160ff0219169083151502179055507fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260016040516116d49190612476565b60405180910390a15b50505050505050505050565b6116f1610a32565b611730576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161172790612080565b60405180910390fd5b611738610cc3565b15611778576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161176f906124d9565b60405180910390fd5b61178061181a565b6117bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117b690611cbc565b60405180910390fd5b600354426117cd9190611dfd565b6006819055507fa895da4b794aeba8d8082db237265459db7b7ffdb5aa7c2332a7c5eafbfae7356006546040516118049190611a62565b60405180910390a1565b60045481565b60025481565b5f600254611826610b10565b11905090565b611834610a32565b611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90612080565b60405180910390fd5b61187b610cc3565b6118ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b1906120e8565b60405180910390fd5b6118c261181a565b15611902576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118f990611db2565b60405180910390fd5b5f6006819055507f50b374cefefbe966ce88eecb3ec50723325b080e27f17d311661c9c07909578860405160405180910390a1565b5f5f60075411905090565b60075481565b5f5f61195261195b565b90508091505090565b5f7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005f1b905090565b5f8115159050919050565b61199881611984565b82525050565b5f6020820190506119b15f83018461198f565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f6119f96119f46119ef846119b7565b6119d6565b6119b7565b9050919050565b5f611a0a826119df565b9050919050565b5f611a1b82611a00565b9050919050565b611a2b81611a11565b82525050565b5f602082019050611a445f830184611a22565b92915050565b5f819050919050565b611a5c81611a4a565b82525050565b5f602082019050611a755f830184611a53565b92915050565b5f5ffd5b5f611a89826119b7565b9050919050565b5f611a9a82611a7f565b9050919050565b611aaa81611a90565b8114611ab4575f5ffd5b50565b5f81359050611ac581611aa1565b92915050565b611ad481611a4a565b8114611ade575f5ffd5b50565b5f81359050611aef81611acb565b92915050565b5f5f5f5f5f60a08688031215611b0e57611b0d611a7b565b5b5f611b1b88828901611ab7565b9550506020611b2c88828901611ab7565b9450506040611b3d88828901611ae1565b9350506060611b4e88828901611ae1565b9250506080611b5f88828901611ae1565b9150509295509295909350565b5f82825260208201905092915050565b7f4d4f44543a204d757374206265206261636b7570206f7261636c6500000000005f82015250565b5f611bb0601b83611b6c565b9150611bbb82611b7c565b602082019050919050565b5f6020820190508181035f830152611bdd81611ba4565b9050919050565b7f4d4f44543a204e6f74206865616c696e670000000000000000000000000000005f82015250565b5f611c18601183611b6c565b9150611c2382611be4565b602082019050919050565b5f6020820190508181035f830152611c4581611c0c565b9050919050565b7f4d4f44543a20446576696174696f6e207468726573686f6c64206e6f74206d655f8201527f7400000000000000000000000000000000000000000000000000000000000000602082015250565b5f611ca6602183611b6c565b9150611cb182611c4c565b604082019050919050565b5f6020820190508181035f830152611cd381611c9a565b9050919050565b7f4d4f44543a20416c7265616479206865616c696e6700000000000000000000005f82015250565b5f611d0e601583611b6c565b9150611d1982611cda565b602082019050919050565b5f6020820190508181035f830152611d3b81611d02565b9050919050565b7f4d4f44543a20446576696174696f6e207468726573686f6c64207374696c6c205f8201527f6d65740000000000000000000000000000000000000000000000000000000000602082015250565b5f611d9c602383611b6c565b9150611da782611d42565b604082019050919050565b5f6020820190508181035f830152611dc981611d90565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611e0782611a4a565b9150611e1283611a4a565b9250828201905080821115611e2a57611e29611dd0565b5b92915050565b7f4d4f44543a204865616c696e672074696d656c6f636b206e6f742070617373655f8201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b5f611e8a602183611b6c565b9150611e9582611e30565b604082019050919050565b5f6020820190508181035f830152611eb781611e7e565b9050919050565b7f4d4f44543a20446576696174696f6e206f6363757272656400000000000000005f82015250565b5f611ef2601883611b6c565b9150611efd82611ebe565b602082019050919050565b5f6020820190508181035f830152611f1f81611ee6565b9050919050565b5f81519050611f3481611acb565b92915050565b5f60208284031215611f4f57611f4e611a7b565b5b5f611f5c84828501611f26565b91505092915050565b5f611f6f82611a4a565b9150611f7a83611a4a565b9250828203905081811115611f9257611f91611dd0565b5b92915050565b5f611fa282611a4a565b9150611fad83611a4a565b9250828202611fbb81611a4a565b91508282048414831517611fd257611fd1611dd0565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61201082611a4a565b915061201b83611a4a565b92508261202b5761202a611fd9565b5b828204905092915050565b7f4d4f44543a204d757374206265207072696d617279206f7261636c65000000005f82015250565b5f61206a601c83611b6c565b915061207582612036565b602082019050919050565b5f6020820190508181035f8301526120978161205e565b9050919050565b7f4d4f44543a204e6f74206368616c6c656e6765640000000000000000000000005f82015250565b5f6120d2601483611b6c565b91506120dd8261209e565b602082019050919050565b5f6020820190508181035f8301526120ff816120c6565b9050919050565b7f4d4f44543a204368616c6c656e67652074696d656c6f636b206e6f74207061735f8201527f7365640000000000000000000000000000000000000000000000000000000000602082015250565b5f612160602383611b6c565b915061216b82612106565b604082019050919050565b5f6020820190508181035f83015261218d81612154565b9050919050565b7f4d4f44543a20446576696174696f6e207265736f6c76656400000000000000005f82015250565b5f6121c8601883611b6c565b91506121d382612194565b602082019050919050565b5f6020820190508181035f8301526121f5816121bc565b9050919050565b7f496e76616c6964207072696d617279206f7261636c65000000000000000000005f82015250565b5f612230601683611b6c565b915061223b826121fc565b602082019050919050565b5f6020820190508181035f83015261225d81612224565b9050919050565b7f496e76616c6964206261636b7570206f7261636c6500000000000000000000005f82015250565b5f612298601583611b6c565b91506122a382612264565b602082019050919050565b5f6020820190508181035f8301526122c58161228c565b9050919050565b7f4f7261636c6573206d75737420626520646966666572656e74000000000000005f82015250565b5f612300601983611b6c565b915061230b826122cc565b602082019050919050565b5f6020820190508181035f83015261232d816122f4565b9050919050565b7f446576696174696f6e207468726573686f6c64206d75737420626520706f73695f8201527f7469766500000000000000000000000000000000000000000000000000000000602082015250565b5f61238e602483611b6c565b915061239982612334565b604082019050919050565b5f6020820190508181035f8301526123bb81612382565b9050919050565b7f4d4f44543a20496e697469616c20646576696174696f6e20746f6f20686967685f82015250565b5f6123f6602083611b6c565b9150612401826123c2565b602082019050919050565b5f6020820190508181035f830152612423816123ea565b9050919050565b5f819050919050565b5f67ffffffffffffffff82169050919050565b5f61246061245b6124568461242a565b6119d6565b612433565b9050919050565b61247081612446565b82525050565b5f6020820190506124895f830184612467565b92915050565b7f4d4f44543a20416c7265616479206368616c6c656e67656400000000000000005f82015250565b5f6124c3601883611b6c565b91506124ce8261248f565b602082019050919050565b5f6020820190508181035f8301526124f0816124b7565b905091905056fea26469706673582212207a11d03de5eff4ce9e9f1ba4261b1181c99ae12bce1ff3340e0b9aaeec43eb8664736f6c634300081c0033","optimization_enabled":false,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"appendCBOR":true,"bytecodeHash":"ipfs","useLiteralContent":false},"optimizer":{"enabled":false,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","ds-test/=lib/morpho-blue-oracles/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","forge-std/=lib/forge-std/src/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","@morpho-blue-oracles/=lib/morpho-blue-oracles/src/","morpho-blue/=lib/morpho-blue-oracles/lib/morpho-blue/","openzeppelin-contracts/=lib/openzeppelin-contracts/","morpho-blue-oracles/=lib/morpho-blue-oracles/src/"],"viaIR":false},"optimization_runs":null,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2025-12-17T18:54:33.317716Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600e575f5ffd5b5061252d8061001c5f395ff3fe608060405234801561000f575f5ffd5b50600436106101c1575f3560e01c8063a035b1fe116100f7578063d2ef739811610095578063de1a69751161006f578063de1a69751461042f578063e2997d6b1461044d578063f8f8b5f014610457578063f9e3444714610475576101c1565b8063d2ef7398146103e9578063d83ed440146103f3578063d94ad83714610411576101c1565b8063bd8f238e116100d1578063bd8f238e14610373578063c2ee5df914610391578063ccc1b9cd146103af578063d13f90b4146103cd576101c1565b8063a035b1fe1461032d578063ad8910061461034b578063b166bf6b14610369576101c1565b8063362a07ae116101645780637ad6d6d51161013e5780637ad6d6d5146102b5578063836efd31146102d357806389ab3532146102f15780639df4d0fe1461030f576101c1565b8063362a07ae1461025b5780633682152b14610279578063498e8b6e14610297576101c1565b80631fc08644116101a05780631fc08644146101f7578063219a94b8146102155780632289445e1461021f5780632f0a577b1461023d576101c1565b8062372f87146101c557806303c01e68146101cf5780630434fe0b146101ed575b5f5ffd5b6101cd610493565b005b6101d761059d565b6040516101e4919061199e565b60405180910390f35b6101f5610614565b005b6101ff61073a565b60405161020c919061199e565b60405180910390f35b61021d610776565b005b61022761095e565b6040516102349190611a31565b60405180910390f35b610245610983565b604051610252919061199e565b60405180910390f35b61026361099f565b6040516102709190611a62565b60405180910390f35b610281610a32565b60405161028e919061199e565b60405180910390f35b61029f610aa8565b6040516102ac9190611a62565b60405180910390f35b6102bd610aae565b6040516102ca919061199e565b60405180910390f35b6102db610aeb565b6040516102e89190611a31565b60405180910390f35b6102f9610b10565b6040516103069190611a62565b60405180910390f35b610317610cc3565b604051610324919061199e565b60405180910390f35b610335610cce565b6040516103429190611a62565b60405180910390f35b610353610e9a565b6040516103609190611a62565b60405180910390f35b610371610f2e565b005b61037b611116565b6040516103889190611a31565b60405180910390f35b61039961113a565b6040516103a6919061199e565b60405180910390f35b6103b7611156565b6040516103c49190611a62565b60405180910390f35b6103e760048036038101906103e29190611af5565b61115c565b005b6103f16116e9565b005b6103fb61180e565b6040516104089190611a62565b60405180910390f35b610419611814565b6040516104269190611a62565b60405180910390f35b61043761181a565b604051610444919061199e565b60405180910390f35b61045561182c565b005b61045f611937565b60405161046c919061199e565b60405180910390f35b61047d611942565b60405161048a9190611a62565b60405180910390f35b61049b61059d565b6104da576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104d190611bc6565b60405180910390fd5b6104e2611937565b610521576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161051890611c2e565b60405180910390fd5b61052961181a565b610568576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161055f90611cbc565b60405180910390fd5b5f6007819055507ff5decdb337f3f69eb4a1610788fd6d8325897945c0f070fef7218c25b84ea90860405160405180910390a1565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b61061c61059d565b61065b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161065290611bc6565b60405180910390fd5b610663611937565b156106a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161069a90611d24565b60405180910390fd5b6106ab61181a565b156106eb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106e290611db2565b60405180910390fd5b600454426106f99190611dfd565b6007819055507fb36d2484c6d35cccf36d46eafe82aa81628f80b9c4e6d1828f5837236a0641bd6007546040516107309190611a62565b60405180910390a1565b5f610743610a32565b80156107535750610752610cc3565b5b801561076157506006544210155b8015610771575061077061181a565b5b905090565b61077e61059d565b6107bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107b490611bc6565b60405180910390fd5b6107c5611937565b610804576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107fb90611c2e565b60405180910390fd5b600754421015610849576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084090611ea0565b60405180910390fd5b61085161181a565b15610891576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161088890611f08565b60405180910390fd5b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60078190555060055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f184591035d84fab784c414962589ca8bf109c62ce76e7b318ca83c16c7c63b6460405160405180910390a2565b60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f61098c610cc3565b801561099a57506006544210155b905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a09573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2d9190611f3a565b905090565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b60035481565b5f610ab761059d565b8015610ac75750610ac6611937565b5b8015610ad557506007544210155b8015610ae65750610ae461181a565b155b905090565b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b7b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9f9190611f3a565b90505f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c0c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c309190611f3a565b90505f8103610c71575f8214610c66577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff610c68565b5f5b92505050610cc0565b5f818310610c8c578183610c859190611f65565b9050610c9b565b8282610c989190611f65565b90505b81670de0b6b3a764000082610cb09190611f98565b610cba9190612006565b93505050505b90565b5f5f60065411905090565b5f60055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610d5857506040513d601f19601f82011682018060405250810190610d559190611f3a565b60015b610e9257610d64610a32565b15610dfe5760015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610dd3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610df79190611f3a565b9050610e97565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e67573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e8b9190611f3a565b9050610e97565b809150505b90565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f05573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f299190611f3a565b905090565b610f36610a32565b610f75576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f6c90612080565b60405180910390fd5b610f7d610cc3565b610fbc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fb3906120e8565b60405180910390fd5b600654421015611001576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ff890612176565b60405180910390fd5b61100961181a565b611048576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161103f906121de565b60405180910390fd5b60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1660055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505f60068190555060055f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f235d3c92abef402ad8969f43056a1212760efee2e4357b1e165a93aed19329e360405160405180910390a2565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b5f611143611937565b801561115157506007544210155b905090565b60065481565b5f611165611948565b90505f815f0160089054906101000a900460ff161590505f825f015f9054906101000a900467ffffffffffffffff1690505f5f8267ffffffffffffffff161480156111ad5750825b90505f60018367ffffffffffffffff161480156111e057505f3073ffffffffffffffffffffffffffffffffffffffff163b145b9050811580156111ee575080155b15611225576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001855f015f6101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508315611272576001855f0160086101000a81548160ff0219169083151502179055505b5f73ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16036112e0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d790612246565b60405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff160361134e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611345906122ae565b60405180910390fd5b8873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16036113bc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113b390612316565b60405180910390fd5b5f88116113fe576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113f5906123a4565b60405180910390fd5b895f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508860015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508760028190555086600381905550856004819055505f8a73ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114dc573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115009190611f3a565b90505f8a73ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561154c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115709190611f3a565b90505f5f82036115b0575f83146115a7577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6115a9565b5f5b90506115fd565b5f8284106115cb5782846115c49190611f65565b90506115da565b83836115d79190611f65565b90505b82670de0b6b3a7640000826115ef9190611f98565b6115f99190612006565b9150505b8a811115611640576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116379061240c565b60405180910390fd5b8c60055f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505083156116dd575f855f0160086101000a81548160ff0219169083151502179055507fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d260016040516116d49190612476565b60405180910390a15b50505050505050505050565b6116f1610a32565b611730576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161172790612080565b60405180910390fd5b611738610cc3565b15611778576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161176f906124d9565b60405180910390fd5b61178061181a565b6117bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117b690611cbc565b60405180910390fd5b600354426117cd9190611dfd565b6006819055507fa895da4b794aeba8d8082db237265459db7b7ffdb5aa7c2332a7c5eafbfae7356006546040516118049190611a62565b60405180910390a1565b60045481565b60025481565b5f600254611826610b10565b11905090565b611834610a32565b611873576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161186a90612080565b60405180910390fd5b61187b610cc3565b6118ba576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118b1906120e8565b60405180910390fd5b6118c261181a565b15611902576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118f990611db2565b60405180910390fd5b5f6006819055507f50b374cefefbe966ce88eecb3ec50723325b080e27f17d311661c9c07909578860405160405180910390a1565b5f5f60075411905090565b60075481565b5f5f61195261195b565b90508091505090565b5f7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005f1b905090565b5f8115159050919050565b61199881611984565b82525050565b5f6020820190506119b15f83018461198f565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f6119f96119f46119ef846119b7565b6119d6565b6119b7565b9050919050565b5f611a0a826119df565b9050919050565b5f611a1b82611a00565b9050919050565b611a2b81611a11565b82525050565b5f602082019050611a445f830184611a22565b92915050565b5f819050919050565b611a5c81611a4a565b82525050565b5f602082019050611a755f830184611a53565b92915050565b5f5ffd5b5f611a89826119b7565b9050919050565b5f611a9a82611a7f565b9050919050565b611aaa81611a90565b8114611ab4575f5ffd5b50565b5f81359050611ac581611aa1565b92915050565b611ad481611a4a565b8114611ade575f5ffd5b50565b5f81359050611aef81611acb565b92915050565b5f5f5f5f5f60a08688031215611b0e57611b0d611a7b565b5b5f611b1b88828901611ab7565b9550506020611b2c88828901611ab7565b9450506040611b3d88828901611ae1565b9350506060611b4e88828901611ae1565b9250506080611b5f88828901611ae1565b9150509295509295909350565b5f82825260208201905092915050565b7f4d4f44543a204d757374206265206261636b7570206f7261636c6500000000005f82015250565b5f611bb0601b83611b6c565b9150611bbb82611b7c565b602082019050919050565b5f6020820190508181035f830152611bdd81611ba4565b9050919050565b7f4d4f44543a204e6f74206865616c696e670000000000000000000000000000005f82015250565b5f611c18601183611b6c565b9150611c2382611be4565b602082019050919050565b5f6020820190508181035f830152611c4581611c0c565b9050919050565b7f4d4f44543a20446576696174696f6e207468726573686f6c64206e6f74206d655f8201527f7400000000000000000000000000000000000000000000000000000000000000602082015250565b5f611ca6602183611b6c565b9150611cb182611c4c565b604082019050919050565b5f6020820190508181035f830152611cd381611c9a565b9050919050565b7f4d4f44543a20416c7265616479206865616c696e6700000000000000000000005f82015250565b5f611d0e601583611b6c565b9150611d1982611cda565b602082019050919050565b5f6020820190508181035f830152611d3b81611d02565b9050919050565b7f4d4f44543a20446576696174696f6e207468726573686f6c64207374696c6c205f8201527f6d65740000000000000000000000000000000000000000000000000000000000602082015250565b5f611d9c602383611b6c565b9150611da782611d42565b604082019050919050565b5f6020820190508181035f830152611dc981611d90565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f611e0782611a4a565b9150611e1283611a4a565b9250828201905080821115611e2a57611e29611dd0565b5b92915050565b7f4d4f44543a204865616c696e672074696d656c6f636b206e6f742070617373655f8201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b5f611e8a602183611b6c565b9150611e9582611e30565b604082019050919050565b5f6020820190508181035f830152611eb781611e7e565b9050919050565b7f4d4f44543a20446576696174696f6e206f6363757272656400000000000000005f82015250565b5f611ef2601883611b6c565b9150611efd82611ebe565b602082019050919050565b5f6020820190508181035f830152611f1f81611ee6565b9050919050565b5f81519050611f3481611acb565b92915050565b5f60208284031215611f4f57611f4e611a7b565b5b5f611f5c84828501611f26565b91505092915050565b5f611f6f82611a4a565b9150611f7a83611a4a565b9250828203905081811115611f9257611f91611dd0565b5b92915050565b5f611fa282611a4a565b9150611fad83611a4a565b9250828202611fbb81611a4a565b91508282048414831517611fd257611fd1611dd0565b5b5092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f61201082611a4a565b915061201b83611a4a565b92508261202b5761202a611fd9565b5b828204905092915050565b7f4d4f44543a204d757374206265207072696d617279206f7261636c65000000005f82015250565b5f61206a601c83611b6c565b915061207582612036565b602082019050919050565b5f6020820190508181035f8301526120978161205e565b9050919050565b7f4d4f44543a204e6f74206368616c6c656e6765640000000000000000000000005f82015250565b5f6120d2601483611b6c565b91506120dd8261209e565b602082019050919050565b5f6020820190508181035f8301526120ff816120c6565b9050919050565b7f4d4f44543a204368616c6c656e67652074696d656c6f636b206e6f74207061735f8201527f7365640000000000000000000000000000000000000000000000000000000000602082015250565b5f612160602383611b6c565b915061216b82612106565b604082019050919050565b5f6020820190508181035f83015261218d81612154565b9050919050565b7f4d4f44543a20446576696174696f6e207265736f6c76656400000000000000005f82015250565b5f6121c8601883611b6c565b91506121d382612194565b602082019050919050565b5f6020820190508181035f8301526121f5816121bc565b9050919050565b7f496e76616c6964207072696d617279206f7261636c65000000000000000000005f82015250565b5f612230601683611b6c565b915061223b826121fc565b602082019050919050565b5f6020820190508181035f83015261225d81612224565b9050919050565b7f496e76616c6964206261636b7570206f7261636c6500000000000000000000005f82015250565b5f612298601583611b6c565b91506122a382612264565b602082019050919050565b5f6020820190508181035f8301526122c58161228c565b9050919050565b7f4f7261636c6573206d75737420626520646966666572656e74000000000000005f82015250565b5f612300601983611b6c565b915061230b826122cc565b602082019050919050565b5f6020820190508181035f83015261232d816122f4565b9050919050565b7f446576696174696f6e207468726573686f6c64206d75737420626520706f73695f8201527f7469766500000000000000000000000000000000000000000000000000000000602082015250565b5f61238e602483611b6c565b915061239982612334565b604082019050919050565b5f6020820190508181035f8301526123bb81612382565b9050919050565b7f4d4f44543a20496e697469616c20646576696174696f6e20746f6f20686967685f82015250565b5f6123f6602083611b6c565b9150612401826123c2565b602082019050919050565b5f6020820190508181035f830152612423816123ea565b9050919050565b5f819050919050565b5f67ffffffffffffffff82169050919050565b5f61246061245b6124568461242a565b6119d6565b612433565b9050919050565b61247081612446565b82525050565b5f6020820190506124895f830184612467565b92915050565b7f4d4f44543a20416c7265616479206368616c6c656e67656400000000000000005f82015250565b5f6124c3601883611b6c565b91506124ce8261248f565b602082019050919050565b5f6020820190508181035f8301526124f0816124b7565b905091905056fea26469706673582212207a11d03de5eff4ce9e9f1ba4261b1181c99ae12bce1ff3340e0b9aaeec43eb8664736f6c634300081c0033","name":"MetaOracleDeviationTimelock","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```solidity\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n *\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Storage of the initializable contract.\n     *\n     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions\n     * when using with upgradeable contracts.\n     *\n     * @custom:storage-location erc7201:openzeppelin.storage.Initializable\n     */\n    struct InitializableStorage {\n        /**\n         * @dev Indicates that the contract has been initialized.\n         */\n        uint64 _initialized;\n        /**\n         * @dev Indicates that the contract is in the process of being initialized.\n         */\n        bool _initializing;\n    }\n\n    // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.Initializable\")) - 1)) & ~bytes32(uint256(0xff))\n    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;\n\n    /**\n     * @dev The contract is already initialized.\n     */\n    error InvalidInitialization();\n\n    /**\n     * @dev The contract is not initializing.\n     */\n    error NotInitializing();\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint64 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any\n     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in\n     * production.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        // Cache values to avoid duplicated sloads\n        bool isTopLevelCall = !$._initializing;\n        uint64 initialized = $._initialized;\n\n        // Allowed calls:\n        // - initialSetup: the contract is not in the initializing state and no previous version was\n        //                 initialized\n        // - construction: the contract is initialized at version 1 (no reinitialization) and the\n        //                 current contract is just being deployed\n        bool initialSetup = initialized == 0 && isTopLevelCall;\n        bool construction = initialized == 1 && address(this).code.length == 0;\n\n        if (!initialSetup && !construction) {\n            revert InvalidInitialization();\n        }\n        $._initialized = 1;\n        if (isTopLevelCall) {\n            $._initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            $._initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint64 version) {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing || $._initialized >= version) {\n            revert InvalidInitialization();\n        }\n        $._initialized = version;\n        $._initializing = true;\n        _;\n        $._initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        _checkInitializing();\n        _;\n    }\n\n    /**\n     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.\n     */\n    function _checkInitializing() internal view virtual {\n        if (!_isInitializing()) {\n            revert NotInitializing();\n        }\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        // solhint-disable-next-line var-name-mixedcase\n        InitializableStorage storage $ = _getInitializableStorage();\n\n        if ($._initializing) {\n            revert InvalidInitialization();\n        }\n        if ($._initialized != type(uint64).max) {\n            $._initialized = type(uint64).max;\n            emit Initialized(type(uint64).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint64) {\n        return _getInitializableStorage()._initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _getInitializableStorage()._initializing;\n    }\n\n    /**\n     * @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.\n     *\n     * NOTE: Consider following the ERC-7201 formula to derive storage locations.\n     */\n    function _initializableStorageSlot() internal pure virtual returns (bytes32) {\n        return INITIALIZABLE_STORAGE;\n    }\n\n    /**\n     * @dev Returns a pointer to the storage namespace.\n     */\n    // solhint-disable-next-line var-name-mixedcase\n    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {\n        bytes32 slot = _initializableStorageSlot();\n        assembly {\n            $.slot := slot\n        }\n    }\n}\n"},{"file_path":"src/interfaces/IMetaOracleDeviationTimelock.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\nimport {IOracle} from \"./IOracle.sol\";\n\n/// @title IMetaOracleDeviationTimelock\n/// @notice Interface for the MetaOracleDeviationTimelock contract, extending IOracle.\ninterface IMetaOracleDeviationTimelock is IOracle {\n    // --- Events (Mirroring implementation) ---\n    event ChallengeStarted(uint256 expiresAt);\n    event ChallengeRevoked();\n    event ChallengeAccepted(address indexed newOracle);\n    event HealingStarted(uint256 expiresAt);\n    event HealingRevoked();\n    event HealingAccepted(address indexed newOracle);\n\n    // --- Configuration --- Accessors for state variables set during initialization\n    function primaryOracle() external view returns (IOracle);\n    function backupOracle() external view returns (IOracle);\n    function primaryPrice() external view returns (uint256);\n    function backupPrice() external view returns (uint256);\n    function deviationThreshold() external view returns (uint256);\n    function challengeTimelockDuration() external view returns (uint256);\n    function healingTimelockDuration() external view returns (uint256);\n\n    // --- State --- Accessors for dynamic state variables\n    function currentOracle() external view returns (IOracle);\n    function challengeExpiresAt() external view returns (uint256);\n    function healingExpiresAt() external view returns (uint256);\n\n    // --- Views ---\n    function isPrimary() external view returns (bool);\n    function isBackup() external view returns (bool);\n    function isChallenged() external view returns (bool);\n    function isHealing() external view returns (bool);\n    function getDeviation() external view returns (uint256);\n    function isDeviant() external view returns (bool);\n    function hasChallengeExpired() external view returns (bool);\n    function hasHealingExpired() external view returns (bool);\n    function canAcceptChallenge() external view returns (bool);\n    function canAcceptHealing() external view returns (bool);\n\n    // --- State Changing Functions ---\n    function challenge() external;\n    function revokeChallenge() external;\n    function acceptChallenge() external;\n    function heal() external;\n    function revokeHealing() external;\n    function acceptHealing() external;\n} "},{"file_path":"src/interfaces/IOracle.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/// @title IOracle\n/// @author Morpho Labs\n/// @custom:contact security@morpho.org\n/// @notice Interface that oracles used by Morpho must implement.\n/// @dev It is the user's responsibility to select markets with safe oracles.\ninterface IOracle {\n    /// @notice Returns the price of 1 asset of collateral token quoted in 1 asset of loan token, scaled by 1e36.\n    /// @dev It corresponds to the price of 10**(collateral token decimals) assets of collateral token quoted in\n    /// 10**(loan token decimals) assets of loan token with `36 + loan token decimals - collateral token decimals`\n    /// decimals of precision.\n    function price() external view returns (uint256);\n} "}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOracle","type":"address"}],"name":"ChallengeAccepted","type":"event"},{"anonymous":false,"inputs":[],"name":"ChallengeRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"expiresAt","type":"uint256"}],"name":"ChallengeStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newOracle","type":"address"}],"name":"HealingAccepted","type":"event"},{"anonymous":false,"inputs":[],"name":"HealingRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"expiresAt","type":"uint256"}],"name":"HealingStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"inputs":[],"name":"acceptChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptHealing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"backupOracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"backupPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canAcceptChallenge","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canAcceptHealing","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"challengeExpiresAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengeTimelockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentOracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deviationThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDeviation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasChallengeExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hasHealingExpired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"heal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"healingExpiresAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healingTimelockDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IOracle","name":"_primaryOracle","type":"address"},{"internalType":"contract IOracle","name":"_backupOracle","type":"address"},{"internalType":"uint256","name":"_deviationThreshold","type":"uint256"},{"internalType":"uint256","name":"_challengeTimelockDuration","type":"uint256"},{"internalType":"uint256","name":"_healingTimelockDuration","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isBackup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isChallenged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDeviant","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isHealing","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPrimary","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primaryOracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primaryPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"revokeChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeHealing","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":null}