{"file_path":"contracts/v3/TheoTUltraOracle.sol","creation_status":"success","source_code":"pragma solidity ^0.8.28;\n\nimport {Ownable2Step, Ownable} from \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport {ITheoTTokenOracle} from \"./ITheoTTokenOracle.sol\";\n/**\n * @notice Oracle to post TUltra exchange rates per epoch\n */\ncontract TheoTUltraOracle is Ownable2Step, ITheoTTokenOracle {\n    /// @notice bps denominator\n    uint256 public constant BPS_DENOMINATOR = 1000000;\n\n    /// @notice tracks current epoch\n    uint256 public latestEpoch;\n\n    /// @notice mapping of epoch number to exchange rate\n    mapping(uint256 => uint256) private epochToExchangeRate;\n\n    constructor(address _initialOwner, uint256 _initialExchangeRate) Ownable(_initialOwner) {\n        require(_initialExchangeRate != 0, \"Initial exchange rate cannot be zero\");\n        latestEpoch = 0;\n        epochToExchangeRate[0] = _initialExchangeRate;\n    }\n\n    function getEpochExchangeRate(uint256 _epoch) external view returns (uint256) {\n        uint256 exchangeRate = epochToExchangeRate[_epoch];\n        require(exchangeRate != 0, \"Exchange rate not set for epoch\");\n        return exchangeRate;\n    }\n\n    function getLatestExchangeRate() external view returns (uint256) {\n        uint256 exchangeRate = epochToExchangeRate[latestEpoch];\n        require(exchangeRate != 0, \"Exchange rate not set for latest epoch\");\n        return exchangeRate;\n    }\n\n    function setExchangeRate(uint256 _epoch, uint256 _exchangeRate) external onlyOwner {\n        require(_epoch <= latestEpoch + 1, \"Can only set previous or next epoch\");\n        require(_exchangeRate != 0, \"Exchange rate cannot be zero\");\n        uint256 updatingEpoch = _epoch;\n        if (_epoch == latestEpoch + 1 || _epoch == 0) {\n            updatingEpoch = latestEpoch + 1;\n            latestEpoch = updatingEpoch;\n        }\n        epochToExchangeRate[updatingEpoch] = _exchangeRate;\n    }\n}\n","deployed_bytecode":"0x6080806040526004361015610012575f80fd5b5f3560e01c90816334d093f61461040357508063715018a6146103a057806379ba50971461031b5780638da5cb5b146102f45780639cb118bf146102d7578063aee1434d14610261578063e1a4521814610244578063e30c39781461021c578063f2fde38b146101a95763f55ecf061461008a575f80fd5b346101a55760403660031901126101a5576024356004356100a9610485565b60025460018101809111610191578082116101405782156100fb578082148281156100f2575b506100e6575b505f52600360205260405f20555f80f35b9050806002555f6100d5565b9050155f6100cf565b60405162461bcd60e51b815260206004820152601c60248201527f45786368616e676520726174652063616e6e6f74206265207a65726f000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602360248201527f43616e206f6e6c79207365742070726576696f7573206f72206e6578742065706044820152620dec6d60eb1b6064820152608490fd5b634e487b7160e01b5f52601160045260245ffd5b5f80fd5b346101a55760203660031901126101a5576004356001600160a01b038116908190036101a5576101d7610485565b600180546001600160a01b031916821790555f80546001600160a01b0316907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227009080a3005b346101a5575f3660031901126101a5576001546040516001600160a01b039091168152602090f35b346101a5575f3660031901126101a5576020604051620f42408152f35b346101a55760203660031901126101a5576004355f52600360205260405f2054801561029257602090604051908152f35b60405162461bcd60e51b815260206004820152601f60248201527f45786368616e67652072617465206e6f742073657420666f722065706f6368006044820152606490fd5b346101a5575f3660031901126101a5576020600254604051908152f35b346101a5575f3660031901126101a5575f546040516001600160a01b039091168152602090f35b346101a5575f3660031901126101a557600154336001600160a01b039091160361038d57600180546001600160a01b03199081169091555f805433928116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b63118cdaa760e01b5f523360045260245ffd5b346101a5575f3660031901126101a5576103b8610485565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101a5575f3660031901126101a5576002545f52600360205260405f205490811561043457602082604051908152f35b62461bcd60e51b815260206004820152602660248201527f45786368616e67652072617465206e6f742073657420666f72206c6174657374604482015265040cae0dec6d60d31b6064820152608490fd5b5f546001600160a01b0316330361038d5756fea264697066735822122017cbd470e57a9300a7ae2cda93070e63eb1bcbe88e8c3b5e69ca217f95bd1aa764736f6c634300081c0033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"prague","libraries":{},"metadata":{"appendCBOR":true,"bytecodeHash":"ipfs","useLiteralContent":false},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/","@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/","forge-std/=lib/forge-std/src/","ds-test/=lib/solidity-http/lib/solidity-stringutils/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/","eth-gas-reporter/=node_modules/eth-gas-reporter/","halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/","hardhat/=node_modules/hardhat/","openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/","openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/","solidity-http/=lib/solidity-http/src/","solidity-stringutils/=lib/solidity-http/lib/solidity-stringutils/"],"viaIR":true},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0x0F21eE679E40123dea03cc64983035Ce24BFfCf3",{"internalType":"address","name":"_initialOwner","type":"address"}],["1030385",{"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"}]],"compiler_version":"v0.8.28+commit.7893614a","is_verified_via_verifier_alliance":false,"verified_at":"2026-04-22T01:44:19.505928Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60803461015357601f61063a38819003918201601f19168301916001600160401b038311848410176101575780849260409485528339810103126101535780516001600160a01b0381169190829003610153576020015190801561014057600180546001600160a01b03199081169091555f80549182168317815560405192916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a381156100f257505f6002819055805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff556040516104ce908161016c8239f35b62461bcd60e51b8152602060048201526024808201527f496e697469616c2065786368616e676520726174652063616e6e6f74206265206044820152637a65726f60e01b6064820152608490fd5b631e4fbdf760e01b5f525f60045260245ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe6080806040526004361015610012575f80fd5b5f3560e01c90816334d093f61461040357508063715018a6146103a057806379ba50971461031b5780638da5cb5b146102f45780639cb118bf146102d7578063aee1434d14610261578063e1a4521814610244578063e30c39781461021c578063f2fde38b146101a95763f55ecf061461008a575f80fd5b346101a55760403660031901126101a5576024356004356100a9610485565b60025460018101809111610191578082116101405782156100fb578082148281156100f2575b506100e6575b505f52600360205260405f20555f80f35b9050806002555f6100d5565b9050155f6100cf565b60405162461bcd60e51b815260206004820152601c60248201527f45786368616e676520726174652063616e6e6f74206265207a65726f000000006044820152606490fd5b60405162461bcd60e51b815260206004820152602360248201527f43616e206f6e6c79207365742070726576696f7573206f72206e6578742065706044820152620dec6d60eb1b6064820152608490fd5b634e487b7160e01b5f52601160045260245ffd5b5f80fd5b346101a55760203660031901126101a5576004356001600160a01b038116908190036101a5576101d7610485565b600180546001600160a01b031916821790555f80546001600160a01b0316907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227009080a3005b346101a5575f3660031901126101a5576001546040516001600160a01b039091168152602090f35b346101a5575f3660031901126101a5576020604051620f42408152f35b346101a55760203660031901126101a5576004355f52600360205260405f2054801561029257602090604051908152f35b60405162461bcd60e51b815260206004820152601f60248201527f45786368616e67652072617465206e6f742073657420666f722065706f6368006044820152606490fd5b346101a5575f3660031901126101a5576020600254604051908152f35b346101a5575f3660031901126101a5575f546040516001600160a01b039091168152602090f35b346101a5575f3660031901126101a557600154336001600160a01b039091160361038d57600180546001600160a01b03199081169091555f805433928116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b63118cdaa760e01b5f523360045260245ffd5b346101a5575f3660031901126101a5576103b8610485565b600180546001600160a01b03199081169091555f80549182168155906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b346101a5575f3660031901126101a5576002545f52600360205260405f205490811561043457602082604051908152f35b62461bcd60e51b815260206004820152602660248201527f45786368616e67652072617465206e6f742073657420666f72206c6174657374604482015265040cae0dec6d60d31b6064820152608490fd5b5f546001600160a01b0316330361038d5756fea264697066735822122017cbd470e57a9300a7ae2cda93070e63eb1bcbe88e8c3b5e69ca217f95bd1aa764736f6c634300081c00330000000000000000000000000f21ee679e40123dea03cc64983035ce24bffcf300000000000000000000000000000000000000000000000000000000000fb8f1","name":"TheoTUltraOracle","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"prague","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"contracts/v3/ITheoTTokenOracle.sol","source_code":"pragma solidity ^0.8.28;\n\ninterface ITheoTTokenOracle {\n    function BPS_DENOMINATOR() external view returns (uint256);\n\n    function getLatestExchangeRate() external view returns (uint256);\n\n    function getEpochExchangeRate(uint256 _epoch) external view returns (uint256);\n}\n"},{"file_path":"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/access/Ownable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    /**\n     * @dev The caller account is not authorized to perform an operation.\n     */\n    error OwnableUnauthorizedAccount(address account);\n\n    /**\n     * @dev The owner is not a valid owner account. (eg. `address(0)`)\n     */\n    error OwnableInvalidOwner(address owner);\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n     */\n    constructor(address initialOwner) {\n        if (initialOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        if (owner() != _msgSender()) {\n            revert OwnableUnauthorizedAccount(_msgSender());\n        }\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby disabling any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        if (newOwner == address(0)) {\n            revert OwnableInvalidOwner(address(0));\n        }\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"},{"file_path":"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {Ownable} from \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This extension of the {Ownable} contract includes a two-step mechanism to transfer\n * ownership, where the new owner must call {acceptOwnership} in order to replace the\n * old one. This can help prevent common mistakes, such as transfers of ownership to\n * incorrect accounts, or to contracts that are unable to interact with the\n * permission system.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n    address private _pendingOwner;\n\n    event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Returns the address of the pending owner.\n     */\n    function pendingOwner() public view virtual returns (address) {\n        return _pendingOwner;\n    }\n\n    /**\n     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n     * Can only be called by the current owner.\n     *\n     * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.\n     */\n    function transferOwnership(address newOwner) public virtual override onlyOwner {\n        _pendingOwner = newOwner;\n        emit OwnershipTransferStarted(owner(), newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual override {\n        delete _pendingOwner;\n        super._transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev The new owner accepts the ownership transfer.\n     */\n    function acceptOwnership() public virtual {\n        address sender = _msgSender();\n        if (pendingOwner() != sender) {\n            revert OwnableUnauthorizedAccount(sender);\n        }\n        _transferOwnership(sender);\n    }\n}\n"},{"file_path":"lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/utils/Context.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    function _contextSuffixLength() internal view virtual returns (uint256) {\n        return 0;\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"}],"name":"getEpochExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epoch","type":"uint256"},{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"name":"setExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x0000000000000000000000000f21ee679e40123dea03cc64983035ce24bffcf300000000000000000000000000000000000000000000000000000000000fb8f1"}