creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "src/UMATrigger.sol": {
        "content": "// SPDX-License-Identifier: Unlicensed\npragma solidity 0.8.22;\n\nimport {BaseTrigger} from \"./abstract/BaseTrigger.sol\";\nimport {OptimisticOracleV2Interface} from \"./interfaces/OptimisticOracleV2Interface.sol\";\nimport {SafeTransferLib} from \"./lib/SafeTransferLib.sol\";\nimport {TriggerState} from \"./structs/StateEnums.sol\";\nimport {IERC20} from \"./interfaces/IERC20.sol\";\n\n/**\n * @notice This is an automated trigger contract which will move into a\n * TRIGGERED state in the event that the UMA Optimistic Oracle answers \"YES\" to\n * a provided query, e.g. \"Was protocol ABCD hacked on or after block 42\". More\n * information about UMA oracles and the lifecycle of queries can be found here:\n * https://docs.umaproject.org/.\n * @dev The high-level lifecycle of a UMA request is as follows:\n * - someone asks a question of the oracle and provides a reward for someone\n * to answer it\n * - users of the UMA prediction market view the question (usually here:\n * https://oracle.umaproject.org/)\n * - someone proposes an answer to the question in hopes of claiming the\n * reward`\n * - users of UMA see the proposed answer and have a chance to dispute it\n * - there is a finite period of time within which to dispute the answer\n * - if the answer is not disputed during this period, the oracle finalizes\n * the answer and the proposer gets the reward\n * - if the answer is disputed, the question is sent to the DVM (Data\n * Verification Mechanism) in which UMA token holders vote on who is right\n * There are four essential players in the above process:\n * 1. Requester: the account that is asking the oracle a question.\n * 2. Proposer: the account that submits an answer to the question.\n * 3. Disputer: the account (if any) that disagrees with the proposed answer.\n * 4. The DVM: a DAO that is the final arbiter of disputed proposals.\n * This trigger plays the first role in this lifecycle. It submits a request for\n * an answer to a yes-or-no question (the query) to the Optimistic Oracle.\n * Questions need to be phrased in such a way that if a \"Yes\" answer is given\n * to them, then this contract will go into a TRIGGERED state. For\n * example, if you wanted to create a safety module for protecting Compound\n * users, you might deploy a UMATrigger with a query like \"Was Compound hacked\n * after block X?\" If the oracle responds with a \"Yes\" answer, this contract\n * would move into the TRIGGERED state and safety modules  with this trigger\n * registered could transition to the TRIGGERED state and potentially payout\n * Compound users.\n * But what if Compound hasn't been hacked? Can't someone just respond \"No\" to\n * the trigger's query? Wouldn't that be the right answer and wouldn't it mean\n * the end of the query lifecycle? Yes. For this exact reason, we have enabled\n * callbacks (see the `priceProposed` function) which will revert in the event\n * that someone attempts to propose a negative answer to the question. We want\n * the queries to remain open indefinitely until there is a positive answer,\n * i.e. \"Yes, there was a hack\". **This should be communicated in the query text.**\n * In the event that a YES answer to a query is disputed and the DVM sides\n * with the disputer (i.e. a NO answer), we immediately re-submit the query to\n * the DVM through another callback (see `priceSettled`). In this way, our query\n * will always be open with the oracle. If/when the event that we are concerned\n * with happens the trigger will immediately be notified.\n */\ncontract UMATrigger is BaseTrigger {\n  using SafeTransferLib for IERC20;\n\n  /// @notice The type of query that will be submitted to the oracle.\n  bytes32 public constant queryIdentifier = bytes32(\"YES_OR_NO_QUERY\");\n\n  /// @notice The UMA Optimistic Oracle.\n  OptimisticOracleV2Interface public immutable oracle;\n\n  /// @notice The identifier used to lookup the UMA Optimistic Oracle with the finder.\n  bytes32 internal constant ORACLE_LOOKUP_IDENTIFIER = bytes32(\"OptimisticOracleV2\");\n\n  /// @notice The query that is sent to the UMA Optimistic Oracle for evaluation.\n  /// It should be phrased so that only a positive answer is appropriate, e.g.\n  /// \"Was protocol ABCD hacked on or after block number 42\". Negative answers\n  /// are disallowed so that queries can remain open in UMA until the events we\n  /// care about happen, if ever.\n  string public query;\n\n  /// @notice The token used to pay the reward to users that propose answers to the query.\n  IERC20 public immutable rewardToken;\n\n  /// @notice The amount of `rewardToken` that must be staked by a user wanting\n  /// to propose or dispute an answer to the query. See UMA's price dispute\n  /// workflow for more information. It's recommended that the bond amount be a\n  /// significant value to deter addresses from proposing malicious, false, or\n  /// otherwise self-interested answers to the query.\n  uint256 public immutable bondAmount;\n\n  /// @notice The window of time in seconds within which a proposed answer may\n  /// be disputed. See UMA's \"customLiveness\" setting for more information. It's\n  /// recommended that the dispute window be fairly long (12-24 hours), given\n  /// the difficulty of assessing expected queries (e.g. \"Was protocol ABCD\n  /// hacked\") and the amount of funds potentially at stake. Additionally,\n  /// proposalDisputeWindow < min(unstakeDelay, withdrawalDelay) is recommended\n  /// to avoid safety modules stakers / depositors front-running safety modules\n  /// becoming triggered.\n  uint256 public immutable proposalDisputeWindow;\n\n  /// @notice The most recent timestamp that the query was submitted to the UMA oracle.\n  uint256 public requestTimestamp;\n\n  /// @notice Default address that will receive any leftover rewards.\n  address public refundRecipient;\n\n  /// @dev Thrown when a negative answer is proposed to the submitted query.\n  error InvalidProposal();\n\n  /// @dev Thrown when the trigger attempts to settle an unsettleable UMA request.\n  error Unsettleable();\n\n  /// @dev Emitted when an answer proposed to the submitted query is disputed\n  /// and a request is sent to the DVM for dispute resolution by UMA tokenholders\n  /// via voting.\n  event ProposalDisputed();\n\n  /// @dev Emitted when the query is resubmitted after a dispute resolution results\n  /// in the proposed answer being rejected (so, the market returns to the active\n  /// state).\n  event QueryResubmitted();\n\n  /// @dev Thrown when the caller is not authorized to perform the action.\n  error Unauthorized();\n\n  /// @dev UMA expects answers to be denominated as wads. So, e.g., a p3 answer\n  /// of 0.5 would be represented as 0.5e18.\n  int256 internal constant AFFIRMATIVE_ANSWER = 1e18;\n\n  /// @param _oracle The UMA Optimistic Oracle.\n  /// @param _query The query that the trigger will send to the UMA Optimistic\n  /// Oracle for evaluation.\n  /// @param _rewardToken The token used to pay the reward to users that propose\n  /// answers to the query. The reward token must be approved by UMA governance.\n  /// Approved tokens can be found with the UMA AddressWhitelist contract on each\n  /// chain supported by UMA.\n  /// @param _refundRecipient Default address that will recieve any leftover\n  /// rewards at UMA query settlement time.\n  /// @param _bondAmount The amount of `rewardToken` that must be staked by a\n  /// user wanting to propose or dispute an answer to the query. See UMA's price\n  /// dispute workflow for more information. It's recommended that the bond\n  /// amount be a significant value to deter addresses from proposing malicious,\n  /// false, or otherwise self-interested answers to the query.\n  /// @param _proposalDisputeWindow The window of time in seconds within which a\n  /// proposed answer may be disputed. See UMA's \"customLiveness\" setting for\n  /// more information. It's recommended that the dispute window be fairly long\n  /// (12-24 hours), given the difficulty of assessing expected queries (e.g.\n  /// \"Was protocol ABCD hacked\") and the amount of funds potentially at stake.\n  constructor(\n    OptimisticOracleV2Interface _oracle,\n    string memory _query,\n    IERC20 _rewardToken,\n    address _refundRecipient,\n    uint256 _bondAmount,\n    uint256 _proposalDisputeWindow\n  ) BaseTrigger() {\n    oracle = _oracle;\n    query = _query;\n    rewardToken = _rewardToken;\n    refundRecipient = _refundRecipient;\n    bondAmount = _bondAmount;\n    proposalDisputeWindow = _proposalDisputeWindow;\n\n    _submitRequestToOracle();\n  }\n\n  /// @notice Submits the trigger query to the UMA Optimistic Oracle for evaluation.\n  function _submitRequestToOracle() internal {\n    uint256 _rewardAmount = rewardToken.balanceOf(address(this));\n    rewardToken.approve(address(oracle), _rewardAmount);\n    requestTimestamp = block.timestamp;\n\n    // The UMA function for submitting a query to the oracle is `requestPrice`\n    // even though not all queries are price queries. Another name for this\n    // function might have been `requestAnswer`.\n    oracle.requestPrice(queryIdentifier, requestTimestamp, bytes(query), rewardToken, _rewardAmount);\n\n    // Set this as an event-based query so that no one can propose the \"too\n    // soon\" answer and so that we automatically get the reward back if there\n    // is a dispute. This allows us to re-query the oracle for ~free.\n    oracle.setEventBased(queryIdentifier, requestTimestamp, bytes(query));\n\n    // Set the amount of rewardTokens that have to be staked in order to answer\n    // the query or dispute an answer to the query.\n    oracle.setBond(queryIdentifier, requestTimestamp, bytes(query), bondAmount);\n\n    // Set the proposal dispute window -- i.e. how long people have to challenge\n    // and answer to the query.\n    oracle.setCustomLiveness(queryIdentifier, requestTimestamp, bytes(query), proposalDisputeWindow);\n\n    // We want to be notified by the UMA oracle when answers and proposed and\n    // when answers are confirmed/settled.\n    oracle.setCallbacks(\n      queryIdentifier,\n      requestTimestamp,\n      bytes(query),\n      true, // Enable the answer-proposed callback.\n      true, // Enable the answer-disputed callback.\n      true // Enable the answer-settled callback.\n    );\n  }\n\n  /// @notice UMA callback for proposals. This function is called by the UMA\n  /// oracle when a new answer is proposed for the query. Its only purpose is to\n  /// prevent people from proposing negative answers and prematurely closing our\n  /// queries. For example, if our query were something like \"Has Compound been\n  /// hacked since block X?\" the correct answer could easily be \"No\" right now.\n  /// But we we don't care if the answer is \"No\". The trigger only cares when\n  /// hacks *actually happen*. So we revert when people try to submit negative\n  /// answers, as negative answers that are undisputed would resolve our query\n  /// and we'd have to pay a new reward to resubmit.\n  /// @param _identifier price identifier being requested.\n  /// @param _timestamp timestamp of the original query request.\n  /// @param _ancillaryData ancillary data of the original query request.\n  function priceProposed(bytes32 _identifier, uint256 _timestamp, bytes memory _ancillaryData) external {\n    // Besides confirming that the caller is the UMA oracle, we also confirm\n    // that the args passed in match the args used to submit our latest query to\n    // UMA. This is done as an extra safeguard that we are responding to an\n    // event related to the specific query we care about. It is possible, for\n    // example, for multiple queries to be submitted to the oracle that differ\n    // only with respect to timestamp. So we want to make sure we know which\n    // query the answer is for.\n    if (\n      msg.sender != address(oracle) || _timestamp != requestTimestamp\n        || keccak256(_ancillaryData) != keccak256(bytes(query)) || _identifier != queryIdentifier\n    ) revert Unauthorized();\n\n    OptimisticOracleV2Interface.Request memory _umaRequest;\n    _umaRequest = oracle.getRequest(address(this), _identifier, _timestamp, _ancillaryData);\n\n    // Revert if the answer was anything other than \"YES\". We don't want to be told\n    // that a hack/exploit has *not* happened yet, or it cannot be determined, etc.\n    if (_umaRequest.proposedPrice != AFFIRMATIVE_ANSWER) revert InvalidProposal();\n\n    // Freeze the trigger so it cannot be added to a safety module, since there's now a real\n    // possibility that we are going to trigger.\n    _updateTriggerState(TriggerState.FROZEN);\n  }\n\n  /// @notice UMA callback for settlement. This code is run when the protocol\n  /// has confirmed an answer to the query.\n  /// @dev This callback is kept intentionally lean, as we don't want to risk\n  /// reverting and blocking settlement.\n  /// @param _identifier price identifier being requested.\n  /// @param _timestamp timestamp of the original query request.\n  /// @param _ancillaryData ancillary data of the original query request.\n  /// @param _answer the oracle's answer to the query.\n  function priceSettled(bytes32 _identifier, uint256 _timestamp, bytes memory _ancillaryData, int256 _answer) external {\n    // See `priceProposed` for why we authorize callers in this way.\n    if (\n      msg.sender != address(oracle) || _timestamp != requestTimestamp\n        || keccak256(_ancillaryData) != keccak256(bytes(query)) || _identifier != queryIdentifier\n    ) revert Unauthorized();\n\n    if (_answer == AFFIRMATIVE_ANSWER) {\n      uint256 _rewardBalance = rewardToken.balanceOf(address(this));\n      if (_rewardBalance > 0) rewardToken.safeTransfer(refundRecipient, _rewardBalance);\n      _updateTriggerState(TriggerState.TRIGGERED);\n    } else {\n      // If the answer was not affirmative, i.e. \"Yes, the protocol was hacked\",\n      // the trigger should return to the ACTIVE state. And we need to resubmit\n      // our query so that we are informed if the event we care about happens in\n      // the future.\n      _updateTriggerState(TriggerState.ACTIVE);\n      _submitRequestToOracle();\n      emit QueryResubmitted();\n    }\n  }\n\n  /// @notice UMA callback for disputes. This code is run when the answer\n  /// proposed to the query is disputed.\n  /// @param _identifier price identifier being requested.\n  /// @param _timestamp timestamp of the original query request.\n  /// @param _ancillaryData ancillary data of the original query request.\n  function priceDisputed(bytes32 _identifier, uint256 _timestamp, bytes memory _ancillaryData, uint256 /* _refund */ )\n    external\n  {\n    // See `priceProposed` for why we authorize callers in this way.\n    if (\n      msg.sender != address(oracle) || _timestamp != requestTimestamp\n        || keccak256(_ancillaryData) != keccak256(bytes(query)) || _identifier != queryIdentifier\n    ) revert Unauthorized();\n\n    emit ProposalDisputed();\n  }\n\n  /// @notice This function attempts to confirm and finalize (i.e. \"settle\") the\n  /// answer to the query with the UMA oracle. It reverts with Unsettleable if\n  /// it cannot settle the query, but does NOT revert if the oracle has already\n  /// settled the query on its own. If the oracle's answer is an\n  /// AFFIRMATIVE_ANSWER, this function will toggle the trigger.\n  function runProgrammaticCheck() external returns (TriggerState) {\n    // Rather than revert when triggered, we simply return the state and exit.\n    // Both behaviors are acceptable, but returning is friendlier to the caller\n    // as they don't need to handle a revert and can simply parse the\n    // transaction's logs to know if the call resulted in a state change.\n    if (state == TriggerState.TRIGGERED) return state;\n\n    bool _oracleHasPrice = oracle.hasPrice(address(this), queryIdentifier, requestTimestamp, bytes(query));\n\n    if (!_oracleHasPrice) revert Unsettleable();\n\n    OptimisticOracleV2Interface.Request memory _umaRequest =\n      oracle.getRequest(address(this), queryIdentifier, requestTimestamp, bytes(query));\n    if (!_umaRequest.settled) {\n      // Give the reward balance to the caller to make up for gas costs and\n      // incentivize keeping safety modules in line with trigger state.\n      refundRecipient = msg.sender;\n\n      // `settle` will cause the oracle to call the trigger's `priceSettled` function.\n      oracle.settle(address(this), queryIdentifier, requestTimestamp, bytes(query));\n    }\n\n    // If the request settled as a result of this call, trigger.state will have\n    // been updated in the priceSettled callback.\n    return state;\n  }\n}\n"
      },
      "src/abstract/BaseTrigger.sol": {
        "content": "// SPDX-License-Identifier: Unlicensed\npragma solidity 0.8.22;\n\nimport {ITrigger} from \"../interfaces/ITrigger.sol\";\nimport {TriggerState} from \"../structs/StateEnums.sol\";\n\n/**\n * @dev Core trigger interface and implementation. All triggers should inherit from this to ensure they conform\n * to the required trigger interface.\n */\nabstract contract BaseTrigger is ITrigger {\n  /// @notice Current trigger state.\n  TriggerState public state;\n\n  /// @dev Thrown when a state update results in an invalid state transition.\n  error InvalidStateTransition();\n\n  /// @dev Child contracts should use this function to handle Trigger state transitions.\n  function _updateTriggerState(TriggerState _newState) internal returns (TriggerState) {\n    if (!_isValidTriggerStateTransition(state, _newState)) revert InvalidStateTransition();\n    state = _newState;\n    emit TriggerStateUpdated(_newState);\n    return _newState;\n  }\n\n  /// @dev Reimplement this function if different state transitions are needed.\n  function _isValidTriggerStateTransition(TriggerState _oldState, TriggerState _newState)\n    internal\n    virtual\n    returns (bool)\n  {\n    // | From / To | ACTIVE      | FROZEN      | PAUSED   | TRIGGERED |\n    // | --------- | ----------- | ----------- | -------- | --------- |\n    // | ACTIVE    | -           | true        | false    | true      |\n    // | FROZEN    | true        | -           | false    | true      |\n    // | PAUSED    | false       | false       | -        | false     | <-- PAUSED is a safety module-level state\n    // | TRIGGERED | false       | false       | false    | -         | <-- TRIGGERED is a terminal state\n\n    if (_oldState == TriggerState.TRIGGERED) return false;\n    // If oldState == newState, return true since the safety module will convert that into a no-op.\n    if (_oldState == _newState) return true;\n    if (_oldState == TriggerState.ACTIVE && _newState == TriggerState.FROZEN) return true;\n    if (_oldState == TriggerState.FROZEN && _newState == TriggerState.ACTIVE) return true;\n    if (_oldState == TriggerState.ACTIVE && _newState == TriggerState.TRIGGERED) return true;\n    if (_oldState == TriggerState.FROZEN && _newState == TriggerState.TRIGGERED) return true;\n    return false;\n  }\n}\n"
      },
      "src/interfaces/OptimisticOracleV2Interface.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n// A named import is used to avoid identifier naming conflicts between IERC20 imports. solc throws a DeclarationError\n// if an interface with the same name is imported twice in a file using different paths, even if they have the\n// same implementation. For example, if a file in the cozy-v2-interfaces submodule that is imported in this project\n// imports an IERC20 interface with \"import src/interfaces/IERC20.sol;\", but in this project we import the same\n// interface with \"import cozy-v2-interfaces/interfaces/IERC20.sol;\", a DeclarationError will be thrown.\nimport { IERC20 } from \"./IERC20.sol\";\nimport \"uma-protocol/packages/core/contracts/data-verification-mechanism/interfaces/FinderInterface.sol\";\n\n/**\n * @title Financial contract facing Oracle interface.\n * @dev Interface used by financial contracts to interact with the Oracle. Voters will use a different interface.\n * @dev Modified from uma-protocol to use Cozy's implementation of IERC20 instead of OpenZeppelin's. Cozy's IERC20\n * conforms to Cozy's implementation of ERC20, which was modified from Solmate to use an initializer to support\n * usage as a minimal proxy.\n */\nabstract contract OptimisticOracleV2Interface {\n    event RequestPrice(\n        address indexed requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes ancillaryData,\n        address currency,\n        uint256 reward,\n        uint256 finalFee\n    );\n    event ProposePrice(\n        address indexed requester,\n        address indexed proposer,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes ancillaryData,\n        int256 proposedPrice,\n        uint256 expirationTimestamp,\n        address currency\n    );\n    event DisputePrice(\n        address indexed requester,\n        address indexed proposer,\n        address indexed disputer,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes ancillaryData,\n        int256 proposedPrice\n    );\n    event Settle(\n        address indexed requester,\n        address indexed proposer,\n        address indexed disputer,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes ancillaryData,\n        int256 price,\n        uint256 payout\n    );\n    // Struct representing the state of a price request.\n    enum State {\n        Invalid, // Never requested.\n        Requested, // Requested, no other actions taken.\n        Proposed, // Proposed, but not expired or disputed yet.\n        Expired, // Proposed, not disputed, past liveness.\n        Disputed, // Disputed, but no DVM price returned yet.\n        Resolved, // Disputed and DVM price is available.\n        Settled // Final price has been set in the contract (can get here from Expired or Resolved).\n    }\n\n    struct RequestSettings {\n        bool eventBased; // True if the request is set to be event-based.\n        bool refundOnDispute; // True if the requester should be refunded their reward on dispute.\n        bool callbackOnPriceProposed; // True if callbackOnPriceProposed callback is required.\n        bool callbackOnPriceDisputed; // True if callbackOnPriceDisputed callback is required.\n        bool callbackOnPriceSettled; // True if callbackOnPriceSettled callback is required.\n        uint256 bond; // Bond that the proposer and disputer must pay on top of the final fee.\n        uint256 customLiveness; // Custom liveness value set by the requester.\n    }\n\n    // Struct representing a price request.\n    struct Request {\n        address proposer; // Address of the proposer.\n        address disputer; // Address of the disputer.\n        IERC20 currency; // ERC20 token used to pay rewards and fees.\n        bool settled; // True if the request is settled.\n        RequestSettings requestSettings; // Custom settings associated with a request.\n        int256 proposedPrice; // Price that the proposer submitted.\n        int256 resolvedPrice; // Price resolved once the request is settled.\n        uint256 expirationTime; // Time at which the request auto-settles without a dispute.\n        uint256 reward; // Amount of the currency to pay to the proposer on settlement.\n        uint256 finalFee; // Final fee to pay to the Store upon request to the DVM.\n    }\n\n    // This value must be <= the Voting contract's `ancillaryBytesLimit` value otherwise it is possible\n    // that a price can be requested to this contract successfully, but cannot be disputed because the DVM refuses\n    // to accept a price request made with ancillary data length over a certain size.\n    uint256 public constant ancillaryBytesLimit = 8192;\n\n    function defaultLiveness() external view virtual returns (uint256);\n\n    function finder() external view virtual returns (FinderInterface);\n\n    function getCurrentTime() external view virtual returns (uint256);\n\n    // Note: this is required so that typechain generates a return value with named fields.\n    mapping(bytes32 => Request) public requests;\n\n    /**\n     * @notice Requests a new price.\n     * @param identifier price identifier being requested.\n     * @param timestamp timestamp of the price being requested.\n     * @param ancillaryData ancillary data representing additional args being passed with the price request.\n     * @param currency ERC20 token used for payment of rewards and fees. Must be approved for use with the DVM.\n     * @param reward reward offered to a successful proposer. Will be pulled from the caller. Note: this can be 0,\n     *               which could make sense if the contract requests and proposes the value in the same call or\n     *               provides its own reward system.\n     * @return totalBond default bond (final fee) + final fee that the proposer and disputer will be required to pay.\n     * This can be changed with a subsequent call to setBond().\n     */\n    function requestPrice(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData,\n        IERC20 currency,\n        uint256 reward\n    ) external virtual returns (uint256 totalBond);\n\n    /**\n     * @notice Set the proposal bond associated with a price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @param bond custom bond amount to set.\n     * @return totalBond new bond + final fee that the proposer and disputer will be required to pay. This can be\n     * changed again with a subsequent call to setBond().\n     */\n    function setBond(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData,\n        uint256 bond\n    ) external virtual returns (uint256 totalBond);\n\n    /**\n     * @notice Sets the request to refund the reward if the proposal is disputed. This can help to \"hedge\" the caller\n     * in the event of a dispute-caused delay. Note: in the event of a dispute, the winner still receives the other's\n     * bond, so there is still profit to be made even if the reward is refunded.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     */\n    function setRefundOnDispute(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) external virtual;\n\n    /**\n     * @notice Sets a custom liveness value for the request. Liveness is the amount of time a proposal must wait before\n     * being auto-resolved.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @param customLiveness new custom liveness.\n     */\n    function setCustomLiveness(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData,\n        uint256 customLiveness\n    ) external virtual;\n\n    /**\n     * @notice Sets the request to be an \"event-based\" request.\n     * @dev Calling this method has a few impacts on the request:\n     *\n     * 1. The timestamp at which the request is evaluated is the time of the proposal, not the timestamp associated\n     *    with the request.\n     *\n     * 2. The proposer cannot propose the \"too early\" value (TOO_EARLY_RESPONSE). This is to ensure that a proposer who\n     *    prematurely proposes a response loses their bond.\n     *\n     * 3. RefundoOnDispute is automatically set, meaning disputes trigger the reward to be automatically refunded to\n     *    the requesting contract.\n     *\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     */\n    function setEventBased(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) external virtual;\n\n    /**\n     * @notice Sets which callbacks should be enabled for the request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @param callbackOnPriceProposed whether to enable the callback onPriceProposed.\n     * @param callbackOnPriceDisputed whether to enable the callback onPriceDisputed.\n     * @param callbackOnPriceSettled whether to enable the callback onPriceSettled.\n     */\n    function setCallbacks(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData,\n        bool callbackOnPriceProposed,\n        bool callbackOnPriceDisputed,\n        bool callbackOnPriceSettled\n    ) external virtual;\n\n    /**\n     * @notice Proposes a price value on another address' behalf. Note: this address will receive any rewards that come\n     * from this proposal. However, any bonds are pulled from the caller.\n     * @param proposer address to set as the proposer.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @param proposedPrice price being proposed.\n     * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n     * the proposer once settled if the proposal is correct.\n     */\n    function proposePriceFor(\n        address proposer,\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData,\n        int256 proposedPrice\n    ) public virtual returns (uint256 totalBond);\n\n    /**\n     * @notice Proposes a price value for an existing price request.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @param proposedPrice price being proposed.\n     * @return totalBond the amount that's pulled from the proposer's wallet as a bond. The bond will be returned to\n     * the proposer once settled if the proposal is correct.\n     */\n    function proposePrice(\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData,\n        int256 proposedPrice\n    ) external virtual returns (uint256 totalBond);\n\n    /**\n     * @notice Disputes a price request with an active proposal on another address' behalf. Note: this address will\n     * receive any rewards that come from this dispute. However, any bonds are pulled from the caller.\n     * @param disputer address to set as the disputer.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return totalBond the amount that's pulled from the caller's wallet as a bond. The bond will be returned to\n     * the disputer once settled if the dispute was value (the proposal was incorrect).\n     */\n    function disputePriceFor(\n        address disputer,\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) public virtual returns (uint256 totalBond);\n\n    /**\n     * @notice Disputes a price value for an existing price request with an active proposal.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return totalBond the amount that's pulled from the disputer's wallet as a bond. The bond will be returned to\n     * the disputer once settled if the dispute was valid (the proposal was incorrect).\n     */\n    function disputePrice(\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) external virtual returns (uint256 totalBond);\n\n    /**\n     * @notice Retrieves a price that was previously requested by a caller. Reverts if the request is not settled\n     * or settleable. Note: this method is not view so that this call may actually settle the price request if it\n     * hasn't been settled.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return resolved price.\n     */\n    function settleAndGetPrice(\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) external virtual returns (int256);\n\n    /**\n     * @notice Attempts to settle an outstanding price request. Will revert if it isn't settleable.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return payout the amount that the \"winner\" (proposer or disputer) receives on settlement. This amount includes\n     * the returned bonds as well as additional rewards.\n     */\n    function settle(\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) external virtual returns (uint256 payout);\n\n    /**\n     * @notice Gets the current data structure containing all information about a price request.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return the Request data structure.\n     */\n    function getRequest(\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) public view virtual returns (Request memory);\n\n    /**\n     * @notice Returns the state of a price request.\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return the State enum value.\n     */\n    function getState(\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) public view virtual returns (State);\n\n    /**\n     * @notice Checks if a given request has resolved or been settled (i.e the optimistic oracle has a price).\n     * @param requester sender of the initial price request.\n     * @param identifier price identifier to identify the existing request.\n     * @param timestamp timestamp to identify the existing request.\n     * @param ancillaryData ancillary data of the price being requested.\n     * @return true if price has resolved or settled, false otherwise.\n     */\n    function hasPrice(\n        address requester,\n        bytes32 identifier,\n        uint256 timestamp,\n        bytes memory ancillaryData\n    ) public view virtual returns (bool);\n\n    function stampAncillaryData(bytes memory ancillaryData, address requester)\n        public\n        view\n        virtual\n        returns (bytes memory);\n}\n"
      },
      "src/lib/SafeTransferLib.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity 0.8.22;\n\n// A named import is used to avoid identifier naming conflicts between IERC20 imports. solc throws a DeclarationError\n// if an interface with the same name is imported twice in a file using different paths, even if they have the\n// same implementation. For example, if a file in the cozy-v2-interfaces submodule that is imported in this project\n// imports an IERC20 interface with \"import src/interfaces/IERC20.sol;\", but in this project we import the same\n// interface with \"import cozy-v2-interfaces/interfaces/IERC20.sol;\", a DeclarationError will be thrown.\nimport { IERC20 } from \"../interfaces/IERC20.sol\";\n\n/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.\n/// @author Solmate (https://github.com/transmissions11/solmate/blob/d155ee8d58f96426f57c015b34dee8a410c1eacc/src/utils/SafeTransferLib.sol)\n/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.\n/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.\n/// @dev Note that this version of solmate's SafeTransferLib uses our own IERC20 interface instead of solmate's ERC20. Cozy's ERC20 was modified\n/// from solmate to use an initializer to support usage as a minimal proxy.\nlibrary SafeTransferLib {\n  // --------------------------------\n  // -------- ETH OPERATIONS --------\n  // --------------------------------\n\n  function safeTransferETH(address to, uint256 amount) internal {\n    bool success;\n\n    assembly {\n      // Transfer the ETH and store if it succeeded or not.\n      success := call(gas(), to, amount, 0, 0, 0, 0)\n    }\n\n    require(success, \"ETH_TRANSFER_FAILED\");\n  }\n\n  // ----------------------------------\n  // -------- ERC20 OPERATIONS --------\n  // ----------------------------------\n\n  function safeTransferFrom(\n    IERC20 token,\n    address from,\n    address to,\n    uint256 amount\n  ) internal {\n    bool success;\n\n    assembly {\n      // Get a pointer to some free memory.\n      let freeMemoryPointer := mload(0x40)\n\n      // Write the abi-encoded calldata into memory, beginning with the function selector.\n      mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)\n      mstore(add(freeMemoryPointer, 4), from) // Append the \"from\" argument.\n      mstore(add(freeMemoryPointer, 36), to) // Append the \"to\" argument.\n      mstore(add(freeMemoryPointer, 68), amount) // Append the \"amount\" argument.\n\n      success := and(\n        // Set success to whether the call reverted, if not we check it either\n        // returned exactly 1 (can't just be non-zero data), or had no return data.\n        or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n        // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.\n        // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n        // Counterintuitively, this call must be positioned second to the or() call in the\n        // surrounding and() call or else returndatasize() will be zero during the computation.\n        call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)\n      )\n    }\n\n    require(success, \"TRANSFER_FROM_FAILED\");\n  }\n\n  function safeTransfer(\n    IERC20 token,\n    address to,\n    uint256 amount\n  ) internal {\n    bool success;\n\n    assembly {\n      // Get a pointer to some free memory.\n      let freeMemoryPointer := mload(0x40)\n\n      // Write the abi-encoded calldata into memory, beginning with the function selector.\n      mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)\n      mstore(add(freeMemoryPointer, 4), to) // Append the \"to\" argument.\n      mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument.\n\n      success := and(\n        // Set success to whether the call reverted, if not we check it either\n        // returned exactly 1 (can't just be non-zero data), or had no return data.\n        or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n        // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n        // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n        // Counterintuitively, this call must be positioned second to the or() call in the\n        // surrounding and() call or else returndatasize() will be zero during the computation.\n        call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n      )\n    }\n\n    require(success, \"TRANSFER_FAILED\");\n  }\n\n  function safeApprove(\n    IERC20 token,\n    address to,\n    uint256 amount\n  ) internal {\n    bool success;\n\n    assembly {\n      // Get a pointer to some free memory.\n      let freeMemoryPointer := mload(0x40)\n\n      // Write the abi-encoded calldata into memory, beginning with the function selector.\n      mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)\n      mstore(add(freeMemoryPointer, 4), to) // Append the \"to\" argument.\n      mstore(add(freeMemoryPointer, 36), amount) // Append the \"amount\" argument.\n\n      success := and(\n        // Set success to whether the call reverted, if not we check it either\n        // returned exactly 1 (can't just be non-zero data), or had no return data.\n        or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),\n        // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.\n        // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.\n        // Counterintuitively, this call must be positioned second to the or() call in the\n        // surrounding and() call or else returndatasize() will be zero during the computation.\n        call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)\n      )\n    }\n\n    require(success, \"APPROVE_FAILED\");\n  }\n}\n"
      },
      "src/structs/StateEnums.sol": {
        "content": "// SPDX-License-Identifier: Unlicensed\npragma solidity 0.8.22;\n\nenum TriggerState {\n  ACTIVE,\n  TRIGGERED,\n  FROZEN\n}\n"
      },
      "src/interfaces/IERC20.sol": {
        "content": "// SPDX-License-Identifier: Unlicensed\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface for ERC20 tokens.\n */\ninterface IERC20 {\n  /// @dev Emitted when the allowance of a `spender` for an `owner` is updated, where `amount` is the new allowance.\n  event Approval(address indexed owner, address indexed spender, uint256 value);\n  /// @dev Emitted when `amount` tokens are moved from `from` to `to`.\n  event Transfer(address indexed from, address indexed to, uint256 value);\n\n  /// @notice Returns the remaining number of tokens that `spender` will be allowed to spend on behalf of `holder`.\n  function allowance(address owner, address spender) external view returns (uint256);\n  /// @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens.\n  function approve(address spender, uint256 amount) external returns (bool);\n  /// @notice Returns the amount of tokens owned by `account`.\n  function balanceOf(address account) external view returns (uint256);\n  /// @notice Returns the decimal places of the token.\n  function decimals() external view returns (uint8);\n  /// @notice Sets `_value` as the allowance of `_spender` over `_owner`s tokens, given a signed approval from the\n  /// owner.\n  function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)\n    external;\n  /// @notice Returns the name of the token.\n  function name() external view returns (string memory);\n  /// @notice Returns the symbol of the token.\n  function symbol() external view returns (string memory);\n  /// @notice Returns the amount of tokens in existence.\n  function totalSupply() external view returns (uint256);\n  /// @notice Moves `_amount` tokens from the caller's account to `_to`.\n  function transfer(address to, uint256 amount) external returns (bool);\n  /// @notice Moves `_amount` tokens from `_from` to `_to` using the allowance mechanism. `_amount` is then deducted\n  /// from the caller's allowance.\n  function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n"
      },
      "src/interfaces/ITrigger.sol": {
        "content": "// SPDX-License-Identifier: Unlicensed\npragma solidity ^0.8.0;\n\nimport {TriggerState} from \"../structs/StateEnums.sol\";\n\n/**\n * @dev The minimal functions a trigger must implement to work with the Cozy Safety Module protocol.\n */\ninterface ITrigger {\n  /// @dev Emitted when a trigger's state is updated.\n  event TriggerStateUpdated(TriggerState indexed state);\n\n  /// @notice The current trigger state.\n  function state() external returns (TriggerState);\n}\n"
      },
      "lib/uma-protocol/packages/core/contracts/data-verification-mechanism/interfaces/FinderInterface.sol": {
        "content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity ^0.8.0;\n\n/**\n * @title Provides addresses of the live contracts implementing certain interfaces.\n * @dev Examples are the Oracle or Store interfaces.\n */\ninterface FinderInterface {\n    /**\n     * @notice Updates the address of the contract that implements `interfaceName`.\n     * @param interfaceName bytes32 encoding of the interface name that is either changed or registered.\n     * @param implementationAddress address of the deployed contract that implements the interface.\n     */\n    function changeImplementationAddress(bytes32 interfaceName, address implementationAddress) external;\n\n    /**\n     * @notice Gets the address of the contract that implements the given `interfaceName`.\n     * @param interfaceName queried interface.\n     * @return implementationAddress address of the deployed contract that implements the interface.\n     */\n    function getImplementationAddress(bytes32 interfaceName) external view returns (address);\n}\n"
      }
    },
    "settings": {
      "remappings": [
        "@openzeppelin/=lib/openzeppelin-contracts/",
        "@chainlink/=lib/chainlink/",
        "chainlink/=lib/chainlink/contracts/",
        "ds-test/=lib/forge-std/lib/ds-test/src/",
        "forge-std/=lib/forge-std/src/",
        "solmate/=lib/solmate/src/",
        "uma-protocol/=lib/uma-protocol/"
      ],
      "optimizer": {
        "enabled": true,
        "runs": 10000000
      },
      "metadata": {
        "useLiteralContent": false,
        "bytecodeHash": "ipfs",
        "appendCBOR": true
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "evmVersion": "paris",
      "viaIR": false,
      "libraries": {}
    }
  }}