{"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 initialDeviation = getDeviation();\n        require(initialDeviation <= _deviationThreshold, \"MODT: Initial deviation too high\");\n\n        currentOracle = _primaryOracle; // Start with the primary oracle\n        challengeExpiresAt = 0;\n        healingExpiresAt = 0;\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 / average(primaryPrice, backupPrice)`.\n    /// Returns 0 if both prices are 0.\n    function getDeviation() public view returns (uint256) {\n        uint256 currentPrimaryPrice = primaryOracle.price();\n        uint256 currentBackupPrice = backupOracle.price();\n\n        // Handle case where both prices are zero\n        if (currentPrimaryPrice == 0 && currentBackupPrice == 0) {\n            return 0;\n        }\n\n        uint256 diff;\n        if (currentPrimaryPrice >= currentBackupPrice) {\n            diff = currentPrimaryPrice - currentBackupPrice;\n        } else {\n            diff = currentBackupPrice - currentPrimaryPrice;\n        }\n\n        // Calculate average of the two prices\n        uint256 average = (currentPrimaryPrice + currentBackupPrice) / 2;\n        \n        // Use uint256 for intermediate multiplication to avoid overflow before division\n        return (diff * 10**18) / average;\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":"0x608060405234801561000f575f5ffd5b50600436106101ba575f3560e01c8063a035b1fe116100f3578063d2ef739811610093578063de1a69751161006e578063de1a697514610357578063e2997d6b1461035f578063f8f8b5f014610367578063f9e3444714610371575f5ffd5b8063d2ef73981461033d578063d83ed44014610345578063d94ad8371461034e575f5ffd5b8063bd8f238e116100ce578063bd8f238e146102fa578063c2ee5df914610319578063ccc1b9cd14610321578063d13f90b41461032a575f5ffd5b8063a035b1fe146102e2578063ad891006146102ea578063b166bf6b146102f2575f5ffd5b8063362a07ae1161015e5780637ad6d6d5116101395780637ad6d6d5146102a8578063836efd31146102b057806389ab3532146102d05780639df4d0fe146102d8575f5ffd5b8063362a07ae146102645780633682152b1461027a578063498e8b6e1461029f575f5ffd5b80631fc08644116101995780631fc0864414610207578063219a94b81461020f5780632289445e146102175780632f0a577b1461025c575f5ffd5b8062372f87146101be57806303c01e68146101c85780630434fe0b146101ff575b5f5ffd5b6101c661037a565b005b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116145b60405190151581526020015b60405180910390f35b6101c66104e4565b6101ea610664565b6101c66106b4565b6005546102379073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f6565b6101ea6108b2565b61026c6108cf565b6040519081526020016101f6565b5f5460055473ffffffffffffffffffffffffffffffffffffffff9182169116146101ea565b61026c60035481565b6101ea61095d565b6001546102379073ffffffffffffffffffffffffffffffffffffffff1681565b61026c6109b5565b60065415156101ea565b61026c610b57565b61026c610d00565b6101c6610d6d565b5f546102379073ffffffffffffffffffffffffffffffffffffffff1681565b6101ea610f69565b61026c60065481565b6101c66103383660046116de565b610f86565b6101c66113a2565b61026c60045481565b61026c60025481565b6101ea61151a565b6101c661152c565b60075415156101ea565b61026c60075481565b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116146103ec5760405162461bcd60e51b815260206004820152601b60248201527f4d4f44543a204d757374206265206261636b7570206f7261636c65000000000060448201526064015b60405180910390fd5b60075461043b5760405162461bcd60e51b815260206004820152601160248201527f4d4f44543a204e6f74206865616c696e6700000000000000000000000000000060448201526064016103e3565b61044361151a565b6104b55760405162461bcd60e51b815260206004820152602160248201527f4d4f44543a20446576696174696f6e207468726573686f6c64206e6f74206d6560448201527f740000000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b5f60078190556040517ff5decdb337f3f69eb4a1610788fd6d8325897945c0f070fef7218c25b84ea9089190a1565b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116146105515760405162461bcd60e51b815260206004820152601b60248201527f4d4f44543a204d757374206265206261636b7570206f7261636c65000000000060448201526064016103e3565b600754156105a15760405162461bcd60e51b815260206004820152601560248201527f4d4f44543a20416c7265616479206865616c696e67000000000000000000000060448201526064016103e3565b6105a961151a565b1561061c5760405162461bcd60e51b815260206004820152602360248201527f4d4f44543a20446576696174696f6e207468726573686f6c64207374696c6c2060448201527f6d6574000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b6004546106299042611754565b60078190556040519081527fb36d2484c6d35cccf36d46eafe82aa81628f80b9c4e6d1828f5837236a0641bd906020015b60405180910390a1565b5f805460055473ffffffffffffffffffffffffffffffffffffffff9182169116148015610692575060065415155b80156106a057506006544210155b80156106af57506106af61151a565b905090565b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116146107215760405162461bcd60e51b815260206004820152601b60248201527f4d4f44543a204d757374206265206261636b7570206f7261636c65000000000060448201526064016103e3565b6007546107705760405162461bcd60e51b815260206004820152601160248201527f4d4f44543a204e6f74206865616c696e6700000000000000000000000000000060448201526064016103e3565b6007544210156107e85760405162461bcd60e51b815260206004820152602160248201527f4d4f44543a204865616c696e672074696d656c6f636b206e6f7420706173736560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b6107f061151a565b1561083d5760405162461bcd60e51b815260206004820152601860248201527f4d4f44543a20446576696174696f6e206f63637572726564000000000000000060448201526064016103e3565b5f8054600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169182179055600782905560405190917f184591035d84fab784c414962589ca8bf109c62ce76e7b318ca83c16c7c63b6491a2565b5f6108be600654151590565b80156106af57505060065442101590565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106af9190611767565b5f61098560015460055473ffffffffffffffffffffffffffffffffffffffff90811691161490565b8015610992575060075415155b80156109a057506007544210155b80156106af57506109af61151a565b15905090565b5f8054604080517fa035b1fe0000000000000000000000000000000000000000000000000000000081529051839273ffffffffffffffffffffffffffffffffffffffff169163a035b1fe9160048083019260209291908290030181865afa158015610a22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a469190611767565b90505f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ab3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ad79190611767565b905081158015610ae5575080155b15610af2575f9250505090565b5f818310610b0b57610b04828461177e565b9050610b18565b610b15838361177e565b90505b5f6002610b258486611754565b610b2f9190611791565b905080610b4483670de0b6b3a76400006117c9565b610b4e9190611791565b94505050505090565b600554604080517fa035b1fe00000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff169163a035b1fe9160048083019260209291908290030181865afa925050508015610c00575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610bfd91810190611767565b60015b610cfb575f5460055473ffffffffffffffffffffffffffffffffffffffff918216911603610c925760015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d5f5f3e3d5ffd5b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d5f5f3e3d5ffd5b919050565b600154604080517fa035b1fe00000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff169163a035b1fe9160048083019260209291908290030181865afa158015610939573d5f5f3e3d5ffd5b5f5460055473ffffffffffffffffffffffffffffffffffffffff918216911614610dd95760405162461bcd60e51b815260206004820152601c60248201527f4d4f44543a204d757374206265207072696d617279206f7261636c650000000060448201526064016103e3565b600654610e285760405162461bcd60e51b815260206004820152601460248201527f4d4f44543a204e6f74206368616c6c656e67656400000000000000000000000060448201526064016103e3565b600654421015610ea05760405162461bcd60e51b815260206004820152602360248201527f4d4f44543a204368616c6c656e67652074696d656c6f636b206e6f742070617360448201527f736564000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b610ea861151a565b610ef45760405162461bcd60e51b815260206004820152601860248201527f4d4f44543a20446576696174696f6e207265736f6c766564000000000000000060448201526064016103e3565b600154600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691821790555f60068190556040517f235d3c92abef402ad8969f43056a1212760efee2e4357b1e165a93aed19329e39190a2565b5f610f75600754151590565b80156106af57505060075442101590565b5f610f8f611691565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f81158015610fbb5750825b90505f8267ffffffffffffffff166001148015610fd75750303b155b905081158015610fe5575080155b1561101c576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561107d5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff8a166110e05760405162461bcd60e51b815260206004820152601660248201527f496e76616c6964207072696d617279206f7261636c650000000000000000000060448201526064016103e3565b73ffffffffffffffffffffffffffffffffffffffff89166111435760405162461bcd60e51b815260206004820152601560248201527f496e76616c6964206261636b7570206f7261636c65000000000000000000000060448201526064016103e3565b8873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16036111be5760405162461bcd60e51b815260206004820152601960248201527f4f7261636c6573206d75737420626520646966666572656e740000000000000060448201526064016103e3565b5f88116112325760405162461bcd60e51b8152602060048201526024808201527f446576696174696f6e207468726573686f6c64206d75737420626520706f736960448201527f746976650000000000000000000000000000000000000000000000000000000060648201526084016103e3565b5f805473ffffffffffffffffffffffffffffffffffffffff808d167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617835560018054918d16919092161790556002899055600388905560048790556112996109b5565b9050888111156112eb5760405162461bcd60e51b815260206004820181905260248201527f4d4f44543a20496e697469616c20646576696174696f6e20746f6f206869676860448201526064016103e3565b50600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8c161790555f600681905560075583156113965784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b5f5460055473ffffffffffffffffffffffffffffffffffffffff91821691161461140e5760405162461bcd60e51b815260206004820152601c60248201527f4d4f44543a204d757374206265207072696d617279206f7261636c650000000060448201526064016103e3565b6006541561145e5760405162461bcd60e51b815260206004820152601860248201527f4d4f44543a20416c7265616479206368616c6c656e676564000000000000000060448201526064016103e3565b61146661151a565b6114d85760405162461bcd60e51b815260206004820152602160248201527f4d4f44543a20446576696174696f6e207468726573686f6c64206e6f74206d6560448201527f740000000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b6003546114e59042611754565b60068190556040519081527fa895da4b794aeba8d8082db237265459db7b7ffdb5aa7c2332a7c5eafbfae7359060200161065a565b5f6002546115266109b5565b11905090565b5f5460055473ffffffffffffffffffffffffffffffffffffffff9182169116146115985760405162461bcd60e51b815260206004820152601c60248201527f4d4f44543a204d757374206265207072696d617279206f7261636c650000000060448201526064016103e3565b6006546115e75760405162461bcd60e51b815260206004820152601460248201527f4d4f44543a204e6f74206368616c6c656e67656400000000000000000000000060448201526064016103e3565b6115ef61151a565b156116625760405162461bcd60e51b815260206004820152602360248201527f4d4f44543a20446576696174696f6e207468726573686f6c64207374696c6c2060448201527f6d6574000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b5f60068190556040517f50b374cefefbe966ce88eecb3ec50723325b080e27f17d311661c9c0790957889190a1565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cfb575f5ffd5b5f5f5f5f5f60a086880312156116f2575f5ffd5b6116fb866116bb565b9450611709602087016116bb565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156116b5576116b5611727565b5f60208284031215611777575f5ffd5b5051919050565b818103818111156116b5576116b5611727565b5f826117c4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b80820281158282048414176116b5576116b561172756fea26469706673582212201c0a3bd2f159cbdbaeb9ac9d42924ce00c75af6061cbfa1c66eb4d86080e450d64736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"appendCBOR":true,"bytecodeHash":"ipfs","useLiteralContent":false},"optimizer":{"enabled":true,"runs":10000},"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":10000,"sourcify_repo_url":null,"decoded_constructor_args":null,"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-02-28T21:03:24.913757Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x6080604052348015600e575f5ffd5b506118168061001c5f395ff3fe608060405234801561000f575f5ffd5b50600436106101ba575f3560e01c8063a035b1fe116100f3578063d2ef739811610093578063de1a69751161006e578063de1a697514610357578063e2997d6b1461035f578063f8f8b5f014610367578063f9e3444714610371575f5ffd5b8063d2ef73981461033d578063d83ed44014610345578063d94ad8371461034e575f5ffd5b8063bd8f238e116100ce578063bd8f238e146102fa578063c2ee5df914610319578063ccc1b9cd14610321578063d13f90b41461032a575f5ffd5b8063a035b1fe146102e2578063ad891006146102ea578063b166bf6b146102f2575f5ffd5b8063362a07ae1161015e5780637ad6d6d5116101395780637ad6d6d5146102a8578063836efd31146102b057806389ab3532146102d05780639df4d0fe146102d8575f5ffd5b8063362a07ae146102645780633682152b1461027a578063498e8b6e1461029f575f5ffd5b80631fc08644116101995780631fc0864414610207578063219a94b81461020f5780632289445e146102175780632f0a577b1461025c575f5ffd5b8062372f87146101be57806303c01e68146101c85780630434fe0b146101ff575b5f5ffd5b6101c661037a565b005b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116145b60405190151581526020015b60405180910390f35b6101c66104e4565b6101ea610664565b6101c66106b4565b6005546102379073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f6565b6101ea6108b2565b61026c6108cf565b6040519081526020016101f6565b5f5460055473ffffffffffffffffffffffffffffffffffffffff9182169116146101ea565b61026c60035481565b6101ea61095d565b6001546102379073ffffffffffffffffffffffffffffffffffffffff1681565b61026c6109b5565b60065415156101ea565b61026c610b57565b61026c610d00565b6101c6610d6d565b5f546102379073ffffffffffffffffffffffffffffffffffffffff1681565b6101ea610f69565b61026c60065481565b6101c66103383660046116de565b610f86565b6101c66113a2565b61026c60045481565b61026c60025481565b6101ea61151a565b6101c661152c565b60075415156101ea565b61026c60075481565b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116146103ec5760405162461bcd60e51b815260206004820152601b60248201527f4d4f44543a204d757374206265206261636b7570206f7261636c65000000000060448201526064015b60405180910390fd5b60075461043b5760405162461bcd60e51b815260206004820152601160248201527f4d4f44543a204e6f74206865616c696e6700000000000000000000000000000060448201526064016103e3565b61044361151a565b6104b55760405162461bcd60e51b815260206004820152602160248201527f4d4f44543a20446576696174696f6e207468726573686f6c64206e6f74206d6560448201527f740000000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b5f60078190556040517ff5decdb337f3f69eb4a1610788fd6d8325897945c0f070fef7218c25b84ea9089190a1565b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116146105515760405162461bcd60e51b815260206004820152601b60248201527f4d4f44543a204d757374206265206261636b7570206f7261636c65000000000060448201526064016103e3565b600754156105a15760405162461bcd60e51b815260206004820152601560248201527f4d4f44543a20416c7265616479206865616c696e67000000000000000000000060448201526064016103e3565b6105a961151a565b1561061c5760405162461bcd60e51b815260206004820152602360248201527f4d4f44543a20446576696174696f6e207468726573686f6c64207374696c6c2060448201527f6d6574000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b6004546106299042611754565b60078190556040519081527fb36d2484c6d35cccf36d46eafe82aa81628f80b9c4e6d1828f5837236a0641bd906020015b60405180910390a1565b5f805460055473ffffffffffffffffffffffffffffffffffffffff9182169116148015610692575060065415155b80156106a057506006544210155b80156106af57506106af61151a565b905090565b60015460055473ffffffffffffffffffffffffffffffffffffffff9182169116146107215760405162461bcd60e51b815260206004820152601b60248201527f4d4f44543a204d757374206265206261636b7570206f7261636c65000000000060448201526064016103e3565b6007546107705760405162461bcd60e51b815260206004820152601160248201527f4d4f44543a204e6f74206865616c696e6700000000000000000000000000000060448201526064016103e3565b6007544210156107e85760405162461bcd60e51b815260206004820152602160248201527f4d4f44543a204865616c696e672074696d656c6f636b206e6f7420706173736560448201527f640000000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b6107f061151a565b1561083d5760405162461bcd60e51b815260206004820152601860248201527f4d4f44543a20446576696174696f6e206f63637572726564000000000000000060448201526064016103e3565b5f8054600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169182179055600782905560405190917f184591035d84fab784c414962589ca8bf109c62ce76e7b318ca83c16c7c63b6491a2565b5f6108be600654151590565b80156106af57505060065442101590565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106af9190611767565b5f61098560015460055473ffffffffffffffffffffffffffffffffffffffff90811691161490565b8015610992575060075415155b80156109a057506007544210155b80156106af57506109af61151a565b15905090565b5f8054604080517fa035b1fe0000000000000000000000000000000000000000000000000000000081529051839273ffffffffffffffffffffffffffffffffffffffff169163a035b1fe9160048083019260209291908290030181865afa158015610a22573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a469190611767565b90505f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ab3573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ad79190611767565b905081158015610ae5575080155b15610af2575f9250505090565b5f818310610b0b57610b04828461177e565b9050610b18565b610b15838361177e565b90505b5f6002610b258486611754565b610b2f9190611791565b905080610b4483670de0b6b3a76400006117c9565b610b4e9190611791565b94505050505090565b600554604080517fa035b1fe00000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff169163a035b1fe9160048083019260209291908290030181865afa925050508015610c00575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252610bfd91810190611767565b60015b610cfb575f5460055473ffffffffffffffffffffffffffffffffffffffff918216911603610c925760015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d5f5f3e3d5ffd5b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a035b1fe6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610939573d5f5f3e3d5ffd5b919050565b600154604080517fa035b1fe00000000000000000000000000000000000000000000000000000000815290515f9273ffffffffffffffffffffffffffffffffffffffff169163a035b1fe9160048083019260209291908290030181865afa158015610939573d5f5f3e3d5ffd5b5f5460055473ffffffffffffffffffffffffffffffffffffffff918216911614610dd95760405162461bcd60e51b815260206004820152601c60248201527f4d4f44543a204d757374206265207072696d617279206f7261636c650000000060448201526064016103e3565b600654610e285760405162461bcd60e51b815260206004820152601460248201527f4d4f44543a204e6f74206368616c6c656e67656400000000000000000000000060448201526064016103e3565b600654421015610ea05760405162461bcd60e51b815260206004820152602360248201527f4d4f44543a204368616c6c656e67652074696d656c6f636b206e6f742070617360448201527f736564000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b610ea861151a565b610ef45760405162461bcd60e51b815260206004820152601860248201527f4d4f44543a20446576696174696f6e207265736f6c766564000000000000000060448201526064016103e3565b600154600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691821790555f60068190556040517f235d3c92abef402ad8969f43056a1212760efee2e4357b1e165a93aed19329e39190a2565b5f610f75600754151590565b80156106af57505060075442101590565b5f610f8f611691565b805490915060ff68010000000000000000820416159067ffffffffffffffff165f81158015610fbb5750825b90505f8267ffffffffffffffff166001148015610fd75750303b155b905081158015610fe5575080155b1561101c576040517ff92ee8a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84547fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000166001178555831561107d5784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000001785555b73ffffffffffffffffffffffffffffffffffffffff8a166110e05760405162461bcd60e51b815260206004820152601660248201527f496e76616c6964207072696d617279206f7261636c650000000000000000000060448201526064016103e3565b73ffffffffffffffffffffffffffffffffffffffff89166111435760405162461bcd60e51b815260206004820152601560248201527f496e76616c6964206261636b7570206f7261636c65000000000000000000000060448201526064016103e3565b8873ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff16036111be5760405162461bcd60e51b815260206004820152601960248201527f4f7261636c6573206d75737420626520646966666572656e740000000000000060448201526064016103e3565b5f88116112325760405162461bcd60e51b8152602060048201526024808201527f446576696174696f6e207468726573686f6c64206d75737420626520706f736960448201527f746976650000000000000000000000000000000000000000000000000000000060648201526084016103e3565b5f805473ffffffffffffffffffffffffffffffffffffffff808d167fffffffffffffffffffffffff000000000000000000000000000000000000000092831617835560018054918d16919092161790556002899055600388905560048790556112996109b5565b9050888111156112eb5760405162461bcd60e51b815260206004820181905260248201527f4d4f44543a20496e697469616c20646576696174696f6e20746f6f206869676860448201526064016103e3565b50600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8c161790555f600681905560075583156113965784547fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050505050565b5f5460055473ffffffffffffffffffffffffffffffffffffffff91821691161461140e5760405162461bcd60e51b815260206004820152601c60248201527f4d4f44543a204d757374206265207072696d617279206f7261636c650000000060448201526064016103e3565b6006541561145e5760405162461bcd60e51b815260206004820152601860248201527f4d4f44543a20416c7265616479206368616c6c656e676564000000000000000060448201526064016103e3565b61146661151a565b6114d85760405162461bcd60e51b815260206004820152602160248201527f4d4f44543a20446576696174696f6e207468726573686f6c64206e6f74206d6560448201527f740000000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b6003546114e59042611754565b60068190556040519081527fa895da4b794aeba8d8082db237265459db7b7ffdb5aa7c2332a7c5eafbfae7359060200161065a565b5f6002546115266109b5565b11905090565b5f5460055473ffffffffffffffffffffffffffffffffffffffff9182169116146115985760405162461bcd60e51b815260206004820152601c60248201527f4d4f44543a204d757374206265207072696d617279206f7261636c650000000060448201526064016103e3565b6006546115e75760405162461bcd60e51b815260206004820152601460248201527f4d4f44543a204e6f74206368616c6c656e67656400000000000000000000000060448201526064016103e3565b6115ef61151a565b156116625760405162461bcd60e51b815260206004820152602360248201527f4d4f44543a20446576696174696f6e207468726573686f6c64207374696c6c2060448201527f6d6574000000000000000000000000000000000000000000000000000000000060648201526084016103e3565b5f60068190556040517f50b374cefefbe966ce88eecb3ec50723325b080e27f17d311661c9c0790957889190a1565b5f807ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005b92915050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610cfb575f5ffd5b5f5f5f5f5f60a086880312156116f2575f5ffd5b6116fb866116bb565b9450611709602087016116bb565b94979496505050506040830135926060810135926080909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156116b5576116b5611727565b5f60208284031215611777575f5ffd5b5051919050565b818103818111156116b5576116b5611727565b5f826117c4577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b80820281158282048414176116b5576116b561172756fea26469706673582212201c0a3bd2f159cbdbaeb9ac9d42924ce00c75af6061cbfa1c66eb4d86080e450d64736f6c634300081c0033","name":"MetaOracleDeviationTimelock","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"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}