{
  "language": "Solidity",
  "sources": {
    "contracts/collateral/Collateral.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/control/unstructured/UInitializable.sol\";\nimport \"@equilibria/root/control/unstructured/UReentrancyGuard.sol\";\nimport \"../interfaces/ICollateral.sol\";\nimport \"./types/OptimisticLedger.sol\";\nimport \"../controller/UControllerProvider.sol\";\n\n/**\n * @title Collateral\n * @notice Manages logic and state for all collateral accounts in the protocol.\n */\ncontract Collateral is ICollateral, UInitializable, UControllerProvider, UReentrancyGuard {\n    /// @dev ERC20 stablecoin for collateral\n    Token18 public immutable token;\n\n    /// @dev Per product collateral state\n    mapping(IProduct => OptimisticLedger) private _products;\n\n    /// @dev Protocol and product fees collected, but not yet claimed\n    mapping(address => UFixed18) public fees;\n\n    /**\n     * @notice Initializes the immutable contract state\n     * @dev Called at implementation instantiate and constant for that implementation.\n     * @param token_ Collateral ERC20 stablecoin address\n     */\n    constructor(Token18 token_) {\n        token = token_;\n    }\n\n    /**\n     * @notice Initializes the contract state\n     * @dev Must be called atomically as part of the upgradeable proxy deployment to\n     *      avoid front-running\n     * @param controller_ Factory contract address\n     */\n    function initialize(IController controller_) external initializer(1) {\n        __UControllerProvider__initialize(controller_);\n        __UReentrancyGuard__initialize();\n    }\n\n    /**\n     * @notice Deposits `amount` collateral from `msg.sender` to `account`'s `product`\n     *         account\n     * @param account Account to deposit the collateral for\n     * @param product Product to credit the collateral to\n     * @param amount Amount of collateral to deposit\n     */\n    function depositTo(address account, IProduct product, UFixed18 amount)\n    external\n    nonReentrant\n    notPaused\n    notZeroAddress(account)\n    isProduct(product)\n    collateralInvariant(account, product)\n    {\n        _products[product].creditAccount(account, amount);\n        token.pull(msg.sender, amount);\n\n        emit Deposit(account, product, amount);\n    }\n\n    /**\n     * @notice Withdraws `amount` collateral from `msg.sender`'s `product` account\n     *         and sends it to `account`\n     * @param account Account to withdraw the collateral to\n     * @param product Product to withdraw the collateral from\n     * @param amount Amount of collateral to withdraw\n     */\n    function withdrawTo(address account, IProduct product, UFixed18 amount)\n    external\n    nonReentrant\n    notPaused\n    notZeroAddress(account)\n    isProduct(product)\n    settleForAccount(msg.sender, product)\n    collateralInvariant(msg.sender, product)\n    maintenanceInvariant(msg.sender, product)\n    {\n        amount = amount.eq(UFixed18Lib.MAX) ? collateral(msg.sender, product) : amount;\n        _products[product].debitAccount(msg.sender, amount);\n        token.push(account, amount);\n\n        emit Withdrawal(msg.sender, product, amount);\n    }\n\n    /**\n     * @notice Liquidates `account`'s `product` collateral account\n     * @dev Account must be under-collateralized, fee returned immediately to `msg.sender`\n     * @param account Account to liquidate\n     * @param product Product to liquidate for\n     */\n    function liquidate(address account, IProduct product)\n    external\n    nonReentrant\n    notPaused\n    isProduct(product)\n    settleForAccount(account, product)\n    {\n        UFixed18 totalMaintenance = product.maintenance(account);\n        UFixed18 totalCollateral = collateral(account, product);\n\n        if (!totalMaintenance.gt(totalCollateral))\n            revert CollateralCantLiquidate(totalMaintenance, totalCollateral);\n\n        product.closeAll(account);\n\n        // claim fee\n        UFixed18 liquidationFee = controller().liquidationFee();\n        UFixed18 fee = UFixed18Lib.min(totalCollateral, totalMaintenance.mul(liquidationFee));\n\n        _products[product].debitAccount(account, fee);\n        token.push(msg.sender, fee);\n\n        emit Liquidation(account, product, msg.sender, fee);\n    }\n\n    /**\n     * @notice Credits `amount` to `account`'s collateral account\n     * @dev Callable only by the corresponding product as part of the settlement flywheel.\n     *      Moves collateral within a product, any collateral leaving the product due to\n     *      fees has already been accounted for in the settleProduct flywheel.\n     *      Debits in excess of the account balance get recorded as shortfall, and can be\n     *      resolved by the product owner as needed.\n     * @param account Account to credit\n     * @param amount Amount to credit the account (can be negative)\n     */\n    function settleAccount(address account, Fixed18 amount) external onlyProduct {\n        IProduct product = IProduct(msg.sender);\n\n        UFixed18 newShortfall = _products[product].settleAccount(account, amount);\n\n        emit AccountSettle(product, account, amount, newShortfall);\n    }\n\n    /**\n     * @notice Debits `amount` from product's total collateral account\n     * @dev Callable only by the corresponding product as part of the settlement flywheel\n     *      Removes collateral from the product as fees.\n     * @param amount Amount to debit from the account\n     */\n    function settleProduct(UFixed18 amount) external onlyProduct {\n        (IProduct product, IController controller) = (IProduct(msg.sender), controller());\n\n        address protocolTreasury = controller.treasury();\n        address productTreasury = controller.treasury(product);\n\n        UFixed18 protocolFee = amount.mul(controller.protocolFee());\n        UFixed18 productFee = amount.sub(protocolFee);\n\n        _products[product].debit(amount);\n        fees[protocolTreasury] = fees[protocolTreasury].add(protocolFee);\n        fees[productTreasury] = fees[productTreasury].add(productFee);\n\n        emit ProductSettle(product, protocolFee, productFee);\n    }\n\n    /**\n     * @notice Returns the balance of `account`'s `product` collateral account\n     * @param account Account to return for\n     * @param product Product to return for\n     * @return The balance of the collateral account\n     */\n    function collateral(address account, IProduct product) public view returns (UFixed18) {\n        return _products[product].balances[account];\n    }\n\n    /**\n     * @notice Returns the total balance of `product`'s collateral\n     * @param product Product to return for\n     * @return The total balance of collateral in the product\n     */\n    function collateral(IProduct product) external view returns (UFixed18) {\n        return _products[product].total;\n    }\n\n    /**\n     * @notice Returns the current shortfall of `product`'s collateral\n     * @param product Product to return for\n     * @return The current shortfall of the product\n     */\n    function shortfall(IProduct product) external view returns (UFixed18) {\n        return _products[product].shortfall;\n    }\n\n    /**\n     * @notice Returns whether `account`'s `product` collateral account can be liquidated\n     * @param account Account to return for\n     * @param product Product to return for\n     * @return Whether the account can be liquidated\n     */\n    function liquidatable(address account, IProduct product) external view returns (bool) {\n        return product.maintenance(account).gt(collateral(account, product));\n    }\n\n    /**\n     * @notice Returns whether `account`'s `product` collateral account can be liquidated\n     *         after the next oracle version settlement\n     * @dev Takes into account the current pre-position on the account\n     * @param account Account to return for\n     * @param product Product to return for\n     * @return Whether the account can be liquidated\n     */\n    function liquidatableNext(address account, IProduct product) external view returns (bool) {\n        return product.maintenanceNext(account).gt(collateral(account, product));\n    }\n\n    /**\n     * @notice Injects additional collateral into a product to resolve shortfall\n     * @dev Shortfall is a measure of settled insolvency in the market\n     *      This hook can be used by the product owner or an insurance fund to re-capitalize an insolvent market\n     * @param product Product to resolve shortfall for\n     * @param amount Amount of shortfall to resolve\n     */\n    function resolveShortfall(IProduct product, UFixed18 amount) external isProduct(product) notPaused {\n        _products[product].resolve(amount);\n        token.pull(msg.sender, amount);\n\n        emit ShortfallResolution(product, amount);\n    }\n\n    /**\n     * @notice Claims all of `msg.sender`'s fees\n     */\n    function claimFee() external notPaused {\n        UFixed18 amount = fees[msg.sender];\n\n        fees[msg.sender] = UFixed18Lib.ZERO;\n        token.push(msg.sender, amount);\n\n        emit FeeClaim(msg.sender, amount);\n    }\n\n    /// @dev Ensure that the address is non-zero\n    modifier notZeroAddress(address account) {\n        if (account == address(0)) revert CollateralZeroAddressError();\n\n        _;\n    }\n\n    /// @dev Ensure that the user has sufficient margin for both current and next maintenance\n    modifier maintenanceInvariant(address account, IProduct product) {\n        _;\n\n        UFixed18 maintenance = product.maintenance(account);\n        UFixed18 maintenanceNext = product.maintenanceNext(account);\n\n        if (UFixed18Lib.max(maintenance, maintenanceNext).gt(collateral(account, product)))\n            revert CollateralInsufficientCollateralError();\n    }\n\n    /// @dev Ensure that the account is either empty or above the collateral minimum\n    modifier collateralInvariant(address account, IProduct product) {\n        _;\n\n        UFixed18 accountCollateral = collateral(account, product);\n        if (!accountCollateral.isZero() && accountCollateral.lt(controller().minCollateral()))\n            revert CollateralUnderLimitError();\n    }\n\n    /// @dev Helper to fully settle an account's state\n    modifier settleForAccount(address account, IProduct product) {\n        product.settleAccount(account);\n\n        _;\n    }\n}\n"
    },
    "@equilibria/root/control/unstructured/UInitializable.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"../../storage/UStorage.sol\";\n\n/**\n * @title UInitializable\n * @notice Library to manage the initialization lifecycle of upgradeable contracts\n * @dev `UInitializable` allows the creation of pseudo-constructors for upgradeable contracts. One\n *      `initializer` should be declared per top-level contract. Child contracts can use the `onlyInitializer`\n *      modifier to tag their internal initialization functions to ensure that they can only be called\n *      from a top-level `initializer` or a constructor.\n */\nabstract contract UInitializable {\n    error UInitializableZeroVersionError();\n    error UInitializableAlreadyInitializedError(uint256 version);\n    error UInitializableNotInitializingError();\n\n    event Initialized(uint256 version);\n\n    /// @dev The initialized flag\n    Uint256Storage private constant _version = Uint256Storage.wrap(keccak256(\"equilibria.root.UInitializable.version\"));\n\n    /// @dev The initializing flag\n    BoolStorage private constant _initializing = BoolStorage.wrap(keccak256(\"equilibria.root.UInitializable.initializing\"));\n\n    /// @dev Can only be called once per version, `version` is 1-indexed\n    modifier initializer(uint256 version) {\n        if (version == 0) revert UInitializableZeroVersionError();\n        if (_version.read() >= version) revert UInitializableAlreadyInitializedError(version);\n\n        _version.store(version);\n        _initializing.store(true);\n\n        _;\n\n        _initializing.store(false);\n        emit Initialized(version);\n    }\n\n    /// @dev Can only be called from an initializer or constructor\n    modifier onlyInitializer() {\n        if (!_constructing() && !_initializing.read()) revert UInitializableNotInitializingError();\n        _;\n    }\n\n    /**\n     * @notice Returns whether the contract is currently being constructed\n     * @dev {Address.isContract} returns false for contracts currently in the process of being constructed\n     * @return Whether the contract is currently being constructed\n     */\n    function _constructing() private view returns (bool) {\n        return !Address.isContract(address(this));\n    }\n}\n"
    },
    "@equilibria/root/control/unstructured/UReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"./UInitializable.sol\";\nimport \"../../storage/UStorage.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n *\n * NOTE: This contract has been extended from the Open Zeppelin library to include an\n *       unstructured storage pattern, so that it can be safely mixed in with upgradeable\n *       contracts without affecting their storage patterns through inheritance.\n */\nabstract contract UReentrancyGuard is UInitializable {\n    error UReentrancyGuardReentrantCallError();\n\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    /**\n     * @dev unstructured storage slot for the reentrancy status\n     */\n    Uint256Storage private constant _status = Uint256Storage.wrap(keccak256(\"equilibria.root.UReentrancyGuard.status\"));\n\n    /**\n     * @dev Initializes the contract setting the status to _NOT_ENTERED.\n     */\n    function __UReentrancyGuard__initialize() internal onlyInitializer {\n        _status.store(_NOT_ENTERED);\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and make it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        // On the first call to nonReentrant, _notEntered will be true\n        if (_status.read() == _ENTERED) revert UReentrancyGuardReentrantCallError();\n\n        // Any calls to nonReentrant after this point will fail\n        _status.store(_ENTERED);\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status.store(_NOT_ENTERED);\n    }\n}\n"
    },
    "contracts/interfaces/ICollateral.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/root/number/types/Fixed18.sol\";\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"./IController.sol\";\nimport \"./IProduct.sol\";\n\ninterface ICollateral {\n    event Deposit(address indexed user, IProduct indexed product, UFixed18 amount);\n    event Withdrawal(address indexed user, IProduct indexed product, UFixed18 amount);\n    event AccountSettle(IProduct indexed product, address indexed account, Fixed18 amount, UFixed18 newShortfall);\n    event ProductSettle(IProduct indexed product, UFixed18 protocolFee, UFixed18 productFee);\n    event Liquidation(address indexed user, IProduct indexed product, address liquidator, UFixed18 fee);\n    event ShortfallResolution(IProduct indexed product, UFixed18 amount);\n    event FeeClaim(address indexed account, UFixed18 amount);\n\n    error CollateralCantLiquidate(UFixed18 totalMaintenance, UFixed18 totalCollateral);\n    error CollateralInsufficientCollateralError();\n    error CollateralUnderLimitError();\n    error CollateralZeroAddressError();\n\n    function token() external view returns (Token18);\n    function fees(address account) external view returns (UFixed18);\n    function initialize(IController controller_) external;\n    function depositTo(address account, IProduct product, UFixed18 amount) external;\n    function withdrawTo(address account, IProduct product, UFixed18 amount) external;\n    function liquidate(address account, IProduct product) external;\n    function settleAccount(address account, Fixed18 amount) external;\n    function settleProduct(UFixed18 amount) external;\n    function collateral(address account, IProduct product) external view returns (UFixed18);\n    function collateral(IProduct product) external view returns (UFixed18);\n    function shortfall(IProduct product) external view returns (UFixed18);\n    function liquidatable(address account, IProduct product) external view returns (bool);\n    function liquidatableNext(address account, IProduct product) external view returns (bool);\n    function resolveShortfall(IProduct product, UFixed18 amount) external;\n    function claimFee() external;\n}\n"
    },
    "contracts/collateral/types/OptimisticLedger.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\n\n/// @dev OptimisticLedger type\nstruct OptimisticLedger {\n    /// @dev Individual account collateral balances\n    mapping(address => UFixed18) balances;\n\n    /// @dev Total ledger collateral balance\n    UFixed18 total;\n\n    /// @dev Total ledger collateral shortfall\n    UFixed18 shortfall;\n}\nusing OptimisticLedgerLib for OptimisticLedger global;\n\n/**\n * @title OptimisticLedgerLib\n * @notice Library that manages a global vs account ledger where the global ledger is settled separately,\n *         and ahead of, the user-level accounts.\n * @dev    Ensures that no more collateral leaves the ledger than goes it, while allowing user-level accounts\n *         to settle as a follow up step. Overdrafts on the user-level are accounted as \"shortall\". Shortfall\n *         in the system is the quantity of insolvency that can be optionally resolved by the ledger owner.\n *         Until the shortfall is resolved, collateral may be withdrawn from the ledger on a FCFS basis. However\n *         once the ledger total has been depleted, users will not be able to withdraw even if they have non-zero\n *         user level balances until the shortfall is resolved, recapitalizing the ledger.\n */\nlibrary OptimisticLedgerLib {\n    /**\n     * @notice Credits `account` with `amount` collateral\n     * @param self The struct to operate on\n     * @param account Account to credit collateral to\n     * @param amount Amount of collateral to credit\n     */\n    function creditAccount(OptimisticLedger storage self, address account, UFixed18 amount) internal {\n        self.balances[account] = self.balances[account].add(amount);\n        self.total = self.total.add(amount);\n    }\n\n    /**\n     * @notice Debits `account` `amount` collateral\n     * @param self The struct to operate on\n     * @param account Account to debit collateral from\n     * @param amount Amount of collateral to debit\n     */\n    function debitAccount(OptimisticLedger storage self, address account, UFixed18 amount) internal {\n        self.balances[account] = self.balances[account].sub(amount);\n        self.total = self.total.sub(amount);\n    }\n\n    /**\n     * @notice Credits `account` with `amount` collateral\n     * @dev Funds come from inside the product, not totals are updated\n     *      Shortfall is created if more funds are debited from an account than exist\n     * @param self The struct to operate on\n     * @param account Account to credit collateral to\n     * @param amount Amount of collateral to credit\n     * @return newShortfall Any new shortfall incurred during this settlement\n     */\n    function settleAccount(OptimisticLedger storage self, address account, Fixed18 amount)\n    internal returns (UFixed18 newShortfall) {\n        Fixed18 newBalance = Fixed18Lib.from(self.balances[account]).add(amount);\n\n        if (newBalance.sign() == -1) {\n            newShortfall = newBalance.abs();\n            newBalance = Fixed18Lib.ZERO;\n        }\n\n        self.balances[account] = newBalance.abs();\n        self.shortfall = self.shortfall.add(newShortfall);\n    }\n\n    /**\n     * @notice Debits ledger globally `amount` collateral\n     * @dev Removes balance from total that is accounted for elsewhere (e.g. product-level accumulators)\n     * @param self The struct to operate on\n     * @param amount Amount of collateral to debit\n     */\n    function debit(OptimisticLedger storage self, UFixed18 amount) internal {\n        self.total = self.total.sub(amount);\n    }\n\n    /**\n     * @notice Reduces the amount of collateral shortfall in the ledger\n     * @param self The struct to operate on\n     * @param amount Amount of shortfall to resolve\n     */\n    function resolve(OptimisticLedger storage self, UFixed18 amount) internal {\n        self.shortfall = self.shortfall.sub(amount);\n        self.total = self.total.add(amount);\n    }\n}\n"
    },
    "contracts/controller/UControllerProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/control/unstructured/UInitializable.sol\";\nimport \"@equilibria/root/storage/UStorage.sol\";\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"../interfaces/IController.sol\";\nimport \"../interfaces/IProduct.sol\";\n\n/**\n * @title UControllerProvider\n * @notice Mix-in that manages a controller pointer and associated permissioning modifiers.\n * @dev Uses unstructured storage so that it is safe to mix-in to upgreadable contracts without modifying\n *      their storage layout.\n */\nabstract contract UControllerProvider is UInitializable {\n    error NotOwnerError(uint256 coordinatorId);\n    error NotProductError(IProduct product);\n    error NotCollateralError();\n    error PausedError();\n    error InvalidControllerError();\n\n    /// @dev The controller contract address\n    AddressStorage private constant _controller = AddressStorage.wrap(keccak256(\"equilibria.perennial.UControllerProvider.controller\"));\n    function controller() public view returns (IController) { return IController(_controller.read()); }\n\n    /**\n     * @notice Initializes the contract state\n     * @param controller_ Protocol Controller contract address\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function __UControllerProvider__initialize(IController controller_) internal onlyInitializer {\n        if (!Address.isContract(address(controller_))) revert InvalidControllerError();\n        _controller.store(address(controller_));\n    }\n\n    /// @dev Only allow a valid product contract to call\n    modifier onlyProduct {\n        if (!controller().isProduct(IProduct(msg.sender))) revert NotProductError(IProduct(msg.sender));\n\n        _;\n    }\n\n    /// @dev Verify that `product` is a valid product contract\n    modifier isProduct(IProduct product) {\n        if (!controller().isProduct(product)) revert NotProductError(product);\n\n        _;\n    }\n\n    /// @dev Only allow the Collateral contract to call\n    modifier onlyCollateral {\n        if (msg.sender != address(controller().collateral())) revert NotCollateralError();\n\n        _;\n    }\n\n    /// @dev Only allow the coordinator owner to call\n    modifier onlyOwner(uint256 coordinatorId) {\n        if (msg.sender != controller().owner(coordinatorId)) revert NotOwnerError(coordinatorId);\n\n        _;\n    }\n\n    /// @dev Only allow if the protocol is currently unpaused\n    modifier notPaused() {\n        if (controller().paused()) revert PausedError();\n\n        _;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/Address.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
    },
    "@equilibria/root/storage/UStorage.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"../number/types/UFixed18.sol\";\n\n/// @dev Stored boolean slot\ntype BoolStorage is bytes32;\nusing BoolStorageLib for BoolStorage global;\n\n/// @dev Stored uint256 slot\ntype Uint256Storage is bytes32;\nusing Uint256StorageLib for Uint256Storage global;\n\n/// @dev Stored int256 slot\ntype Int256Storage is bytes32;\nusing Int256StorageLib for Int256Storage global;\n\n/// @dev Stored address slot\ntype AddressStorage is bytes32;\nusing AddressStorageLib for AddressStorage global;\n\n/// @dev Stored bytes32 slot\ntype Bytes32Storage is bytes32;\nusing Bytes32StorageLib for Bytes32Storage global;\n\n/**\n * @title BoolStorageLib\n * @notice Library to manage storage and retrival of a boolean at a fixed storage slot\n */\nlibrary BoolStorageLib {\n    /**\n     * @notice Retrieves the stored value\n     * @param self Storage slot\n     * @return value Stored bool value\n     */\n    function read(BoolStorage self) internal view returns (bool value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    /**\n     * @notice Stores the value at the specific slot\n     * @param self Storage slot\n     * @param value boolean value to store\n     */\n    function store(BoolStorage self, bool value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n\n/**\n * @title Uint256StorageLib\n * @notice Library to manage storage and retrival of an uint256 at a fixed storage slot\n */\nlibrary Uint256StorageLib {\n    /**\n     * @notice Retrieves the stored value\n     * @param self Storage slot\n     * @return value Stored uint256 value\n     */\n    function read(Uint256Storage self) internal view returns (uint256 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    /**\n     * @notice Stores the value at the specific slot\n     * @param self Storage slot\n     * @param value uint256 value to store\n     */\n    function store(Uint256Storage self, uint256 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n\n/**\n * @title Int256StorageLib\n * @notice Library to manage storage and retrival of an int256 at a fixed storage slot\n */\nlibrary Int256StorageLib {\n    /**\n     * @notice Retrieves the stored value\n     * @param self Storage slot\n     * @return value Stored int256 value\n     */\n    function read(Int256Storage self) internal view returns (int256 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    /**\n     * @notice Stores the value at the specific slot\n     * @param self Storage slot\n     * @param value int256 value to store\n     */\n    function store(Int256Storage self, int256 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n\n/**\n * @title AddressStorageLib\n * @notice Library to manage storage and retrival of an address at a fixed storage slot\n */\nlibrary AddressStorageLib {\n    /**\n     * @notice Retrieves the stored value\n     * @param self Storage slot\n     * @return value Stored address value\n     */\n    function read(AddressStorage self) internal view returns (address value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    /**\n     * @notice Stores the value at the specific slot\n     * @param self Storage slot\n     * @param value address value to store\n     */\n    function store(AddressStorage self, address value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n\n/**\n * @title Bytes32StorageLib\n * @notice Library to manage storage and retrival of a bytes32 at a fixed storage slot\n */\nlibrary Bytes32StorageLib {\n    /**\n     * @notice Retrieves the stored value\n     * @param self Storage slot\n     * @return value Stored bytes32 value\n     */\n    function read(Bytes32Storage self) internal view returns (bytes32 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    /**\n     * @notice Stores the value at the specific slot\n     * @param self Storage slot\n     * @param value bytes32 value to store\n     */\n    function store(Bytes32Storage self, bytes32 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n"
    },
    "@equilibria/root/number/types/UFixed18.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"./Fixed18.sol\";\nimport \"./PackedUFixed18.sol\";\n\n/// @dev UFixed18 type\ntype UFixed18 is uint256;\nusing UFixed18Lib for UFixed18 global;\ntype UFixed18Storage is bytes32;\nusing UFixed18StorageLib for UFixed18Storage global;\n\n/**\n * @title UFixed18Lib\n * @notice Library for the unsigned fixed-decimal type.\n */\nlibrary UFixed18Lib {\n    error UFixed18UnderflowError(int256 value);\n    error UFixed18PackingOverflowError(uint256 value);\n\n    uint256 private constant BASE = 1e18;\n    UFixed18 public constant ZERO = UFixed18.wrap(0);\n    UFixed18 public constant ONE = UFixed18.wrap(BASE);\n    UFixed18 public constant MAX = UFixed18.wrap(type(uint256).max);\n\n    /**\n     * @notice Creates a unsigned fixed-decimal from a signed fixed-decimal\n     * @param a Signed fixed-decimal\n     * @return New unsigned fixed-decimal\n     */\n    function from(Fixed18 a) internal pure returns (UFixed18) {\n        int256 value = Fixed18.unwrap(a);\n        if (value < 0) revert UFixed18UnderflowError(value);\n        return UFixed18.wrap(uint256(value));\n    }\n\n    /**\n     * @notice Creates a unsigned fixed-decimal from a unsigned integer\n     * @param a Unsigned number\n     * @return New unsigned fixed-decimal\n     */\n    function from(uint256 a) internal pure returns (UFixed18) {\n        return UFixed18.wrap(a * BASE);\n    }\n\n    /**\n     * @notice Creates a packed unsigned fixed-decimal from an unsigned fixed-decimal\n     * @param a unsigned fixed-decimal\n     * @return New packed unsigned fixed-decimal\n     */\n    function pack(UFixed18 a) internal pure returns (PackedUFixed18) {\n        uint256 value = UFixed18.unwrap(a);\n        if (value > type(uint128).max) revert UFixed18PackingOverflowError(value);\n        return PackedUFixed18.wrap(uint128(value));\n    }\n\n    /**\n     * @notice Returns whether the unsigned fixed-decimal is equal to zero.\n     * @param a Unsigned fixed-decimal\n     * @return Whether the unsigned fixed-decimal is zero.\n     */\n    function isZero(UFixed18 a) internal pure returns (bool) {\n        return UFixed18.unwrap(a) == 0;\n    }\n\n    /**\n     * @notice Adds two unsigned fixed-decimals `a` and `b` together\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Resulting summed unsigned fixed-decimal\n     */\n    function add(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(UFixed18.unwrap(a) + UFixed18.unwrap(b));\n    }\n\n    /**\n     * @notice Subtracts unsigned fixed-decimal `b` from `a`\n     * @param a Unsigned fixed-decimal to subtract from\n     * @param b Unsigned fixed-decimal to subtract\n     * @return Resulting subtracted unsigned fixed-decimal\n     */\n    function sub(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(UFixed18.unwrap(a) - UFixed18.unwrap(b));\n    }\n\n    /**\n     * @notice Multiplies two unsigned fixed-decimals `a` and `b` together\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Resulting multiplied unsigned fixed-decimal\n     */\n    function mul(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(UFixed18.unwrap(a) * UFixed18.unwrap(b) / BASE);\n    }\n\n    /**\n     * @notice Divides unsigned fixed-decimal `a` by `b`\n     * @param a Unsigned fixed-decimal to divide\n     * @param b Unsigned fixed-decimal to divide by\n     * @return Resulting divided unsigned fixed-decimal\n     */\n    function div(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(UFixed18.unwrap(a) * BASE / UFixed18.unwrap(b));\n    }\n\n    /**\n     * @notice Divides unsigned fixed-decimal `a` by `b`\n     * @dev Does not revert on divide-by-0, instead returns `ONE` for `0/0` and `MAX` for `n/0`.\n     * @param a Unsigned fixed-decimal to divide\n     * @param b Unsigned fixed-decimal to divide by\n     * @return Resulting divided unsigned fixed-decimal\n     */\n    function unsafeDiv(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        if (isZero(b)) {\n            return isZero(a) ? ONE : MAX;\n        } else {\n            return div(a, b);\n        }\n    }\n\n    /**\n     * @notice Computes a * b / c without loss of precision due to BASE conversion\n     * @param a First unsigned fixed-decimal\n     * @param b Unsigned number to multiply by\n     * @param c Unsigned number to divide by\n     * @return Resulting computation\n     */\n    function muldiv(UFixed18 a, uint256 b, uint256 c) internal pure returns (UFixed18) {\n        return muldiv(a, UFixed18.wrap(b), UFixed18.wrap(c));\n    }\n\n    /**\n     * @notice Computes a * b / c without loss of precision due to BASE conversion\n     * @param a First unsigned fixed-decimal\n     * @param b Unsigned fixed-decimal to multiply by\n     * @param c Unsigned fixed-decimal to divide by\n     * @return Resulting computation\n     */\n    function muldiv(UFixed18 a, UFixed18 b, UFixed18 c) internal pure returns (UFixed18) {\n        return UFixed18.wrap(UFixed18.unwrap(a) * UFixed18.unwrap(b) / UFixed18.unwrap(c));\n    }\n\n    /**\n     * @notice Returns whether unsigned fixed-decimal `a` is equal to `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Whether `a` is equal to `b`\n     */\n    function eq(UFixed18 a, UFixed18 b) internal pure returns (bool) {\n        return compare(a, b) == 1;\n    }\n\n    /**\n     * @notice Returns whether unsigned fixed-decimal `a` is greater than `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Whether `a` is greater than `b`\n     */\n    function gt(UFixed18 a, UFixed18 b) internal pure returns (bool) {\n        return compare(a, b) == 2;\n    }\n\n    /**\n     * @notice Returns whether unsigned fixed-decimal `a` is less than `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Whether `a` is less than `b`\n     */\n    function lt(UFixed18 a, UFixed18 b) internal pure returns (bool) {\n        return compare(a, b) == 0;\n    }\n\n    /**\n     * @notice Returns whether unsigned fixed-decimal `a` is greater than or equal to `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Whether `a` is greater than or equal to `b`\n     */\n    function gte(UFixed18 a, UFixed18 b) internal pure returns (bool) {\n        return gt(a, b) || eq(a, b);\n    }\n\n    /**\n     * @notice Returns whether unsigned fixed-decimal `a` is less than or equal to `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Whether `a` is less than or equal to `b`\n     */\n    function lte(UFixed18 a, UFixed18 b) internal pure returns (bool) {\n        return lt(a, b) || eq(a, b);\n    }\n\n    /**\n     * @notice Compares the unsigned fixed-decimals `a` and `b`\n     * @dev Returns: 2 for greater than\n     *               1 for equal to\n     *               0 for less than\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Compare result of `a` and `b`\n     */\n    function compare(UFixed18 a, UFixed18 b) internal pure returns (uint256) {\n        (uint256 au, uint256 bu) = (UFixed18.unwrap(a), UFixed18.unwrap(b));\n        if (au > bu) return 2;\n        if (au < bu) return 0;\n        return 1;\n    }\n\n    /**\n     * @notice Returns a unsigned fixed-decimal representing the ratio of `a` over `b`\n     * @param a First unsigned number\n     * @param b Second unsigned number\n     * @return Ratio of `a` over `b`\n     */\n    function ratio(uint256 a, uint256 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(a * BASE / b);\n    }\n\n    /**\n     * @notice Returns the minimum of unsigned fixed-decimals `a` and `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Minimum of `a` and `b`\n     */\n    function min(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(Math.min(UFixed18.unwrap(a), UFixed18.unwrap(b)));\n    }\n\n    /**\n     * @notice Returns the maximum of unsigned fixed-decimals `a` and `b`\n     * @param a First unsigned fixed-decimal\n     * @param b Second unsigned fixed-decimal\n     * @return Maximum of `a` and `b`\n     */\n    function max(UFixed18 a, UFixed18 b) internal pure returns (UFixed18) {\n        return UFixed18.wrap(Math.max(UFixed18.unwrap(a), UFixed18.unwrap(b)));\n    }\n\n    /**\n     * @notice Converts the unsigned fixed-decimal into an integer, truncating any decimal portion\n     * @param a Unsigned fixed-decimal\n     * @return Truncated unsigned number\n     */\n    function truncate(UFixed18 a) internal pure returns (uint256) {\n        return UFixed18.unwrap(a) / BASE;\n    }\n}\n\nlibrary UFixed18StorageLib {\n    function read(UFixed18Storage self) internal view returns (UFixed18 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    function store(UFixed18Storage self, UFixed18 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/Math.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a >= b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a / b + (a % b == 0 ? 0 : 1);\n    }\n}\n"
    },
    "@equilibria/root/number/types/Fixed18.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/utils/math/SignedMath.sol\";\nimport \"./UFixed18.sol\";\nimport \"./PackedFixed18.sol\";\n\n/// @dev Fixed18 type\ntype Fixed18 is int256;\nusing Fixed18Lib for Fixed18 global;\ntype Fixed18Storage is bytes32;\nusing Fixed18StorageLib for Fixed18Storage global;\n\n/**\n * @title Fixed18Lib\n * @notice Library for the signed fixed-decimal type.\n */\nlibrary Fixed18Lib {\n    error Fixed18OverflowError(uint256 value);\n    error Fixed18PackingOverflowError(int256 value);\n    error Fixed18PackingUnderflowError(int256 value);\n\n    int256 private constant BASE = 1e18;\n    Fixed18 public constant ZERO = Fixed18.wrap(0);\n    Fixed18 public constant ONE = Fixed18.wrap(BASE);\n    Fixed18 public constant NEG_ONE = Fixed18.wrap(-1 * BASE);\n    Fixed18 public constant MAX = Fixed18.wrap(type(int256).max);\n    Fixed18 public constant MIN = Fixed18.wrap(type(int256).min);\n\n    /**\n     * @notice Creates a signed fixed-decimal from an unsigned fixed-decimal\n     * @param a Unsigned fixed-decimal\n     * @return New signed fixed-decimal\n     */\n    function from(UFixed18 a) internal pure returns (Fixed18) {\n        uint256 value = UFixed18.unwrap(a);\n        if (value > uint256(type(int256).max)) revert Fixed18OverflowError(value);\n        return Fixed18.wrap(int256(value));\n    }\n\n    /**\n     * @notice Creates a signed fixed-decimal from a sign and an unsigned fixed-decimal\n     * @param s Sign\n     * @param m Unsigned fixed-decimal magnitude\n     * @return New signed fixed-decimal\n     */\n    function from(int256 s, UFixed18 m) internal pure returns (Fixed18) {\n        if (s > 0) return from(m);\n        if (s < 0) return Fixed18.wrap(-1 * Fixed18.unwrap(from(m)));\n        return ZERO;\n    }\n\n    /**\n     * @notice Creates a signed fixed-decimal from a signed integer\n     * @param a Signed number\n     * @return New signed fixed-decimal\n     */\n    function from(int256 a) internal pure returns (Fixed18) {\n        return Fixed18.wrap(a * BASE);\n    }\n\n    /**\n     * @notice Creates a packed signed fixed-decimal from an signed fixed-decimal\n     * @param a signed fixed-decimal\n     * @return New packed signed fixed-decimal\n     */\n    function pack(Fixed18 a) internal pure returns (PackedFixed18) {\n        int256 value = Fixed18.unwrap(a);\n        if (value > type(int128).max) revert Fixed18PackingOverflowError(value);\n        if (value < type(int128).min) revert Fixed18PackingUnderflowError(value);\n        return PackedFixed18.wrap(int128(value));\n    }\n\n    /**\n     * @notice Returns whether the signed fixed-decimal is equal to zero.\n     * @param a Signed fixed-decimal\n     * @return Whether the signed fixed-decimal is zero.\n     */\n    function isZero(Fixed18 a) internal pure returns (bool) {\n        return Fixed18.unwrap(a) == 0;\n    }\n\n    /**\n     * @notice Adds two signed fixed-decimals `a` and `b` together\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Resulting summed signed fixed-decimal\n     */\n    function add(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(Fixed18.unwrap(a) + Fixed18.unwrap(b));\n    }\n\n    /**\n     * @notice Subtracts signed fixed-decimal `b` from `a`\n     * @param a Signed fixed-decimal to subtract from\n     * @param b Signed fixed-decimal to subtract\n     * @return Resulting subtracted signed fixed-decimal\n     */\n    function sub(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(Fixed18.unwrap(a) - Fixed18.unwrap(b));\n    }\n\n    /**\n     * @notice Multiplies two signed fixed-decimals `a` and `b` together\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Resulting multiplied signed fixed-decimal\n     */\n    function mul(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(Fixed18.unwrap(a) * Fixed18.unwrap(b) / BASE);\n    }\n\n    /**\n     * @notice Divides signed fixed-decimal `a` by `b`\n     * @param a Signed fixed-decimal to divide\n     * @param b Signed fixed-decimal to divide by\n     * @return Resulting divided signed fixed-decimal\n     */\n    function div(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(Fixed18.unwrap(a) * BASE / Fixed18.unwrap(b));\n    }\n\n    /**\n     * @notice Divides unsigned fixed-decimal `a` by `b`\n     * @dev Does not revert on divide-by-0, instead returns `ONE` for `0/0`, `MAX` for `n/0`, and `MIN` for `-n/0`.\n     * @param a Unsigned fixed-decimal to divide\n     * @param b Unsigned fixed-decimal to divide by\n     * @return Resulting divided unsigned fixed-decimal\n     */\n    function unsafeDiv(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        if (isZero(b)) {\n            if (gt(a, ZERO)) return MAX;\n            if (lt(a, ZERO)) return MIN;\n            return ONE;\n        } else {\n            return div(a, b);\n        }\n    }\n\n    /**\n     * @notice Computes a * b / c without loss of precision due to BASE conversion\n     * @param a First signed fixed-decimal\n     * @param b Signed number to multiply by\n     * @param c Signed number to divide by\n     * @return Resulting computation\n     */\n    function muldiv(Fixed18 a, int256 b, int256 c) internal pure returns (Fixed18) {\n        return muldiv(a, Fixed18.wrap(b), Fixed18.wrap(c));\n    }\n\n    /**\n     * @notice Computes a * b / c without loss of precision due to BASE conversion\n     * @param a First signed fixed-decimal\n     * @param b Signed fixed-decimal to multiply by\n     * @param c Signed fixed-decimal to divide by\n     * @return Resulting computation\n     */\n    function muldiv(Fixed18 a, Fixed18 b, Fixed18 c) internal pure returns (Fixed18) {\n        return Fixed18.wrap(Fixed18.unwrap(a) * Fixed18.unwrap(b) / Fixed18.unwrap(c));\n    }\n\n    /**\n     * @notice Returns whether signed fixed-decimal `a` is equal to `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Whether `a` is equal to `b`\n     */\n    function eq(Fixed18 a, Fixed18 b) internal pure returns (bool) {\n        return compare(a, b) == 1;\n    }\n\n    /**\n     * @notice Returns whether signed fixed-decimal `a` is greater than `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Whether `a` is greater than `b`\n     */\n    function gt(Fixed18 a, Fixed18 b) internal pure returns (bool) {\n        return compare(a, b) == 2;\n    }\n\n    /**\n     * @notice Returns whether signed fixed-decimal `a` is less than `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Whether `a` is less than `b`\n     */\n    function lt(Fixed18 a, Fixed18 b) internal pure returns (bool) {\n        return compare(a, b) == 0;\n    }\n\n    /**\n     * @notice Returns whether signed fixed-decimal `a` is greater than or equal to `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Whether `a` is greater than or equal to `b`\n     */\n    function gte(Fixed18 a, Fixed18 b) internal pure returns (bool) {\n        return gt(a, b) || eq(a, b);\n    }\n\n    /**\n     * @notice Returns whether signed fixed-decimal `a` is less than or equal to `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Whether `a` is less than or equal to `b`\n     */\n    function lte(Fixed18 a, Fixed18 b) internal pure returns (bool) {\n        return lt(a, b) || eq(a, b);\n    }\n\n    /**\n     * @notice Compares the signed fixed-decimals `a` and `b`\n     * @dev Returns: 2 for greater than\n     *               1 for equal to\n     *               0 for less than\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Compare result of `a` and `b`\n     */\n    function compare(Fixed18 a, Fixed18 b) internal pure returns (uint256) {\n        (int256 au, int256 bu) = (Fixed18.unwrap(a), Fixed18.unwrap(b));\n        if (au > bu) return 2;\n        if (au < bu) return 0;\n        return 1;\n    }\n\n    /**\n     * @notice Returns a signed fixed-decimal representing the ratio of `a` over `b`\n     * @param a First signed number\n     * @param b Second signed number\n     * @return Ratio of `a` over `b`\n     */\n    function ratio(int256 a, int256 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(a * BASE / b);\n    }\n\n    /**\n     * @notice Returns the minimum of signed fixed-decimals `a` and `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Minimum of `a` and `b`\n     */\n    function min(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(SignedMath.min(Fixed18.unwrap(a), Fixed18.unwrap(b)));\n    }\n\n    /**\n     * @notice Returns the maximum of signed fixed-decimals `a` and `b`\n     * @param a First signed fixed-decimal\n     * @param b Second signed fixed-decimal\n     * @return Maximum of `a` and `b`\n     */\n    function max(Fixed18 a, Fixed18 b) internal pure returns (Fixed18) {\n        return Fixed18.wrap(SignedMath.max(Fixed18.unwrap(a), Fixed18.unwrap(b)));\n    }\n\n    /**\n     * @notice Converts the signed fixed-decimal into an integer, truncating any decimal portion\n     * @param a Signed fixed-decimal\n     * @return Truncated signed number\n     */\n    function truncate(Fixed18 a) internal pure returns (int256) {\n        return Fixed18.unwrap(a) / BASE;\n    }\n\n    /**\n     * @notice Returns the sign of the signed fixed-decimal\n     * @dev Returns: -1 for negative\n     *                0 for zero\n     *                1 for positive\n     * @param a Signed fixed-decimal\n     * @return Sign of the signed fixed-decimal\n     */\n    function sign(Fixed18 a) internal pure returns (int256) {\n        if (Fixed18.unwrap(a) > 0) return 1;\n        if (Fixed18.unwrap(a) < 0) return -1;\n        return 0;\n    }\n\n    /**\n     * @notice Returns the absolute value of the signed fixed-decimal\n     * @param a Signed fixed-decimal\n     * @return Absolute value of the signed fixed-decimal\n     */\n    function abs(Fixed18 a) internal pure returns (UFixed18) {\n        return UFixed18.wrap(SignedMath.abs(Fixed18.unwrap(a)));\n    }\n}\n\nlibrary Fixed18StorageLib {\n    function read(Fixed18Storage self) internal view returns (Fixed18 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    function store(Fixed18Storage self, Fixed18 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n"
    },
    "@equilibria/root/number/types/PackedUFixed18.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"./UFixed18.sol\";\n\n/// @dev PackedUFixed18 type\ntype PackedUFixed18 is uint128;\nusing PackedUFixed18Lib for PackedUFixed18 global;\n\n/**\n * @title PackedUFixed18Lib\n * @dev A packed version of the UFixed18 which takes up half the storage space (two PackedUFixed18 can be packed\n *      into a single slot). Only valid within the range 0 <= x <= 3.4028237e+20.\n * @notice Library for the packed unsigned fixed-decimal type.\n */\nlibrary PackedUFixed18Lib {\n    PackedUFixed18 public constant MAX = PackedUFixed18.wrap(type(uint128).max);\n\n    /**\n     * @notice Creates an unpacked unsigned fixed-decimal from a packed unsigned fixed-decimal\n     * @param self packed unsigned fixed-decimal\n     * @return New unpacked unsigned fixed-decimal\n     */\n    function unpack(PackedUFixed18 self) internal pure returns (UFixed18) {\n        return UFixed18.wrap(uint256(PackedUFixed18.unwrap(self)));\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/SignedMath.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n    /**\n     * @dev Returns the largest of two signed numbers.\n     */\n    function max(int256 a, int256 b) internal pure returns (int256) {\n        return a >= b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two signed numbers.\n     */\n    function min(int256 a, int256 b) internal pure returns (int256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two signed numbers without overflow.\n     * The result is rounded towards zero.\n     */\n    function average(int256 a, int256 b) internal pure returns (int256) {\n        // Formula from the book \"Hacker's Delight\"\n        int256 x = (a & b) + ((a ^ b) >> 1);\n        return x + (int256(uint256(x) >> 255) & (a ^ b));\n    }\n\n    /**\n     * @dev Returns the absolute unsigned value of a signed value.\n     */\n    function abs(int256 n) internal pure returns (uint256) {\n        unchecked {\n            // must be unchecked in order to support `n = type(int256).min`\n            return uint256(n >= 0 ? n : -n);\n        }\n    }\n}\n"
    },
    "@equilibria/root/number/types/PackedFixed18.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"./Fixed18.sol\";\n\n/// @dev PackedFixed18 type\ntype PackedFixed18 is int128;\nusing PackedFixed18Lib for PackedFixed18 global;\n\n/**\n * @title PackedFixed18Lib\n * @dev A packed version of the Fixed18 which takes up half the storage space (two PackedFixed18 can be packed\n *      into a single slot). Only valid within the range -1.7014118e+20 <= x <= 1.7014118e+20.\n * @notice Library for the packed signed fixed-decimal type.\n */\nlibrary PackedFixed18Lib {\n    PackedFixed18 public constant MAX = PackedFixed18.wrap(type(int128).max);\n    PackedFixed18 public constant MIN = PackedFixed18.wrap(type(int128).min);\n\n    /**\n     * @notice Creates an unpacked signed fixed-decimal from a packed signed fixed-decimal\n     * @param self packed signed fixed-decimal\n     * @return New unpacked signed fixed-decimal\n     */\n    function unpack(PackedFixed18 self) internal pure returns (Fixed18) {\n        return Fixed18.wrap(int256(PackedFixed18.unwrap(self)));\n    }\n}\n"
    },
    "@equilibria/root/token/types/Token18.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"../../number/types/UFixed18.sol\";\n\n/// @dev Token18\ntype Token18 is address;\nusing Token18Lib for Token18 global;\ntype Token18Storage is bytes32;\nusing Token18StorageLib for Token18Storage global;\n\n/**\n * @title Token18Lib\n * @notice Library to manage 18-decimal ERC20s that is compliant with the fixed-decimal types.\n * @dev Maintains significant gas savings over other Token implementations since no conversion take place\n */\nlibrary Token18Lib {\n    using SafeERC20 for IERC20;\n\n    Token18 public constant ZERO = Token18.wrap(address(0));\n\n    /**\n     * @notice Returns whether a token is the zero address\n     * @param self Token to check for\n     * @return Whether the token is the zero address\n     */\n    function isZero(Token18 self) internal pure returns (bool) {\n        return Token18.unwrap(self) == Token18.unwrap(ZERO);\n    }\n\n    /**\n     * @notice Returns whether the two tokens are equal\n     * @param a First token to compare\n     * @param b Second token to compare\n     * @return Whether the two tokens are equal\n     */\n    function eq(Token18 a, Token18 b) internal pure returns (bool) {\n        return Token18.unwrap(a) ==  Token18.unwrap(b);\n    }\n\n    /**\n     * @notice Approves `grantee` to spend infinite tokens from the caller\n     * @param self Token to transfer\n     * @param grantee Address to allow spending\n     */\n    function approve(Token18 self, address grantee) internal {\n        IERC20(Token18.unwrap(self)).safeApprove(grantee, type(uint256).max);\n    }\n\n    /**\n     * @notice Approves `grantee` to spend `amount` tokens from the caller\n     * @dev There are important race conditions to be aware of when using this function\n            with values other than 0. This will revert if moving from non-zero to non-zero amounts\n            See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a55b7d13722e7ce850b626da2313f3e66ca1d101/contracts/token/ERC20/IERC20.sol#L57\n     * @param self Token to transfer\n     * @param grantee Address to allow spending\n     * @param amount Amount of tokens to approve to spend\n     */\n    function approve(Token18 self, address grantee, UFixed18 amount) internal {\n        IERC20(Token18.unwrap(self)).safeApprove(grantee, UFixed18.unwrap(amount));\n    }\n\n    /**\n     * @notice Transfers all held tokens from the caller to the `recipient`\n     * @param self Token to transfer\n     * @param recipient Address to receive the tokens\n     */\n    function push(Token18 self, address recipient) internal {\n        push(self, recipient, balanceOf(self, address(this)));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the caller to the `recipient`\n     * @param self Token to transfer\n     * @param recipient Address to transfer tokens to\n     * @param amount Amount of tokens to transfer\n     */\n    function push(Token18 self, address recipient, UFixed18 amount) internal {\n        IERC20(Token18.unwrap(self)).safeTransfer(recipient, UFixed18.unwrap(amount));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the `benefactor` to the caller\n     * @dev Reverts if trying to pull Ether\n     * @param self Token to transfer\n     * @param benefactor Address to transfer tokens from\n     * @param amount Amount of tokens to transfer\n     */\n    function pull(Token18 self, address benefactor, UFixed18 amount) internal {\n        IERC20(Token18.unwrap(self)).safeTransferFrom(benefactor, address(this), UFixed18.unwrap(amount));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the `benefactor` to `recipient`\n     * @dev Reverts if trying to pull Ether\n     * @param self Token to transfer\n     * @param benefactor Address to transfer tokens from\n     * @param recipient Address to transfer tokens to\n     * @param amount Amount of tokens to transfer\n     */\n    function pullTo(Token18 self, address benefactor, address recipient, UFixed18 amount) internal {\n        IERC20(Token18.unwrap(self)).safeTransferFrom(benefactor, recipient, UFixed18.unwrap(amount));\n    }\n\n    /**\n     * @notice Returns the name of the token\n     * @param self Token to check for\n     * @return Token name\n     */\n    function name(Token18 self) internal view returns (string memory) {\n        return IERC20Metadata(Token18.unwrap(self)).name();\n    }\n\n    /**\n     * @notice Returns the symbol of the token\n     * @param self Token to check for\n     * @return Token symbol\n     */\n    function symbol(Token18 self) internal view returns (string memory) {\n        return IERC20Metadata(Token18.unwrap(self)).symbol();\n    }\n\n    /**\n     * @notice Returns the `self` token balance of the caller\n     * @param self Token to check for\n     * @return Token balance of the caller\n     */\n    function balanceOf(Token18 self) internal view returns (UFixed18) {\n        return balanceOf(self, address(this));\n    }\n\n    /**\n     * @notice Returns the `self` token balance of `account`\n     * @param self Token to check for\n     * @param account Account to check\n     * @return Token balance of the account\n     */\n    function balanceOf(Token18 self, address account) internal view returns (UFixed18) {\n        return UFixed18.wrap(IERC20(Token18.unwrap(self)).balanceOf(account));\n    }\n}\n\nlibrary Token18StorageLib {\n    function read(Token18Storage self) internal view returns (Token18 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    function store(Token18Storage self, Token18 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n"
    },
    "contracts/interfaces/IController.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@openzeppelin/contracts/proxy/beacon/IBeacon.sol\";\nimport \"./ICollateral.sol\";\nimport \"./IIncentivizer.sol\";\nimport \"./IProduct.sol\";\nimport \"./types/PayoffDefinition.sol\";\n\ninterface IController {\n    /// @dev Coordinator of a one or many products\n    struct Coordinator {\n        /// @dev Pending owner of the product, can accept ownership\n        address pendingOwner;\n\n        /// @dev Owner of the product, allowed to update select parameters\n        address owner;\n\n        /// @dev Treasury of the product, collects fees\n        address treasury;\n    }\n\n    event CollateralUpdated(ICollateral newCollateral);\n    event IncentivizerUpdated(IIncentivizer newIncentivizer);\n    event ProductBeaconUpdated(IBeacon newProductBeacon);\n    event ProtocolFeeUpdated(UFixed18 newProtocolFee);\n    event MinFundingFeeUpdated(UFixed18 newMinFundingFee);\n    event LiquidationFeeUpdated(UFixed18 newLiquidationFee);\n    event IncentivizationFeeUpdated(UFixed18 newIncentivizationFee);\n    event MinCollateralUpdated(UFixed18 newMinCollateral);\n    event ProgramsPerProductUpdated(uint256 newProgramsPerProduct);\n    event PauserUpdated(address newPauser);\n    event PausedUpdated(bool newPaused);\n    event CoordinatorPendingOwnerUpdated(uint256 indexed coordinatorId, address newPendingOwner);\n    event CoordinatorOwnerUpdated(uint256 indexed coordinatorId, address newOwner);\n    event CoordinatorTreasuryUpdated(uint256 indexed coordinatorId, address newTreasury);\n    event CoordinatorCreated(uint256 indexed coordinatorId, address owner);\n    event ProductCreated(IProduct indexed product, IProduct.ProductInfo productInfo);\n\n    error ControllerNoZeroCoordinatorError();\n    error ControllerNotPauserError();\n    error ControllerNotOwnerError(uint256 controllerId);\n    error ControllerNotPendingOwnerError(uint256 controllerId);\n    error ControllerInvalidProtocolFeeError();\n    error ControllerInvalidMinFundingFeeError();\n    error ControllerInvalidLiquidationFeeError();\n    error ControllerInvalidIncentivizationFeeError();\n    error ControllerNotContractAddressError();\n\n    function collateral() external view returns (ICollateral);\n    function incentivizer() external view returns (IIncentivizer);\n    function productBeacon() external view returns (IBeacon);\n    function coordinators(uint256 collateralId) external view returns (Coordinator memory);\n    function coordinatorFor(IProduct product) external view returns (uint256);\n    function protocolFee() external view returns (UFixed18);\n    function minFundingFee() external view returns (UFixed18);\n    function liquidationFee() external view returns (UFixed18);\n    function incentivizationFee() external view returns (UFixed18);\n    function minCollateral() external view returns (UFixed18);\n    function programsPerProduct() external view returns (uint256);\n    function pauser() external view returns (address);\n    function paused() external view returns (bool);\n    function initialize(ICollateral collateral_, IIncentivizer incentivizer_, IBeacon productBeacon_) external;\n    function createCoordinator() external returns (uint256);\n    function updateCoordinatorPendingOwner(uint256 coordinatorId, address newPendingOwner) external;\n    function acceptCoordinatorOwner(uint256 coordinatorId) external;\n    function updateCoordinatorTreasury(uint256 coordinatorId, address newTreasury) external;\n    function createProduct(uint256 coordinatorId, IProduct.ProductInfo calldata productInfo) external returns (IProduct);\n    function updateCollateral(ICollateral newCollateral) external;\n    function updateIncentivizer(IIncentivizer newIncentivizer) external;\n    function updateProductBeacon(IBeacon newProductBeacon) external;\n    function updateProtocolFee(UFixed18 newProtocolFee) external;\n    function updateMinFundingFee(UFixed18 newMinFundingFee) external;\n    function updateLiquidationFee(UFixed18 newLiquidationFee) external;\n    function updateIncentivizationFee(UFixed18 newIncentivizationFee) external;\n    function updateMinCollateral(UFixed18 newMinCollateral) external;\n    function updateProgramsPerProduct(uint256 newProductsPerProduct) external;\n    function updatePauser(address newPauser) external;\n    function updatePaused(bool newPaused) external;\n    function isProduct(IProduct product) external view returns (bool);\n    function owner() external view returns (address);\n    function owner(uint256 coordinatorId) external view returns (address);\n    function owner(IProduct product) external view returns (address);\n    function treasury() external view returns (address);\n    function treasury(uint256 coordinatorId) external view returns (address);\n    function treasury(IProduct product) external view returns (address);\n}\n"
    },
    "contracts/interfaces/IProduct.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/root/curve/types/JumpRateUtilizationCurve.sol\";\nimport \"./IPayoffProvider.sol\";\nimport \"./IParamProvider.sol\";\nimport \"./types/PayoffDefinition.sol\";\nimport \"./types/Position.sol\";\nimport \"./types/PrePosition.sol\";\nimport \"./types/Accumulator.sol\";\n\ninterface IProduct is IPayoffProvider, IParamProvider {\n    /// @dev Product Creation parameters\n    struct ProductInfo {\n        /// @dev name of the product\n        string name;\n\n        /// @dev symbol of the product\n        string symbol;\n\n        /// @dev product payoff definition\n        PayoffDefinition payoffDefinition;\n\n        /// @dev oracle address\n        IOracleProvider oracle;\n\n        /// @dev product maintenance ratio\n        UFixed18 maintenance;\n\n        /// @dev product funding fee\n        UFixed18 fundingFee;\n\n        /// @dev product maker fee\n        UFixed18 makerFee;\n\n        /// @dev product taker fee\n        UFixed18 takerFee;\n\n        /// @dev product maker limit\n        UFixed18 makerLimit;\n\n        /// @dev utulization curve definition\n        JumpRateUtilizationCurve utilizationCurve;\n    }\n\n    event Settle(uint256 preVersion, uint256 toVersion);\n    event AccountSettle(address indexed account, uint256 preVersion, uint256 toVersion);\n    event MakeOpened(address indexed account, uint256 version, UFixed18 amount);\n    event TakeOpened(address indexed account, uint256 version, UFixed18 amount);\n    event MakeClosed(address indexed account, uint256 version, UFixed18 amount);\n    event TakeClosed(address indexed account, uint256 version, UFixed18 amount);\n    event ClosedUpdated(bool indexed newClosed, uint256 version);\n\n    error ProductInsufficientLiquidityError(UFixed18 socializationFactor);\n    error ProductDoubleSidedError();\n    error ProductOverClosedError();\n    error ProductInsufficientCollateralError();\n    error ProductInLiquidationError();\n    error ProductMakerOverLimitError();\n    error ProductOracleBootstrappingError();\n    error ProductNotOwnerError();\n    error ProductInvalidOracle();\n    error ProductClosedError();\n\n    function name() external view returns (string memory);\n    function symbol() external view returns (string memory);\n    function initialize(ProductInfo calldata productInfo_) external;\n    function settle() external;\n    function settleAccount(address account) external;\n    function openTake(UFixed18 amount) external;\n    function closeTake(UFixed18 amount) external;\n    function openMake(UFixed18 amount) external;\n    function closeMake(UFixed18 amount) external;\n    function closeAll(address account) external;\n    function maintenance(address account) external view returns (UFixed18);\n    function maintenanceNext(address account) external view returns (UFixed18);\n    function isClosed(address account) external view returns (bool);\n    function isLiquidating(address account) external view returns (bool);\n    function position(address account) external view returns (Position memory);\n    function pre(address account) external view returns (PrePosition memory);\n    function latestVersion() external view returns (uint256);\n    function positionAtVersion(uint256 oracleVersion) external view returns (Position memory);\n    function pre() external view returns (PrePosition memory);\n    function valueAtVersion(uint256 oracleVersion) external view returns (Accumulator memory);\n    function shareAtVersion(uint256 oracleVersion) external view returns (Accumulator memory);\n    function latestVersion(address account) external view returns (uint256);\n    function rate(Position memory position) external view returns (Fixed18);\n    function closed() external view returns (bool);\n    function updateClosed(bool newClosed) external;\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n    /**\n     * @dev Must return an address that can be used as a delegate call target.\n     *\n     * {BeaconProxy} will check that this address is a contract.\n     */\n    function implementation() external view returns (address);\n}\n"
    },
    "contracts/interfaces/IIncentivizer.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./types/ProgramInfo.sol\";\nimport \"./IController.sol\";\nimport \"./IProduct.sol\";\n\ninterface IIncentivizer {\n    event ProgramCreated(IProduct indexed product, uint256 indexed programId, ProgramInfo programInfo, UFixed18 programFeeAmount);\n    event ProgramStarted(IProduct indexed product, uint256 indexed programId, uint256 version);\n    event ProgramComplete(IProduct indexed product, uint256 indexed programId, uint256 version);\n    event Claim(IProduct indexed product, address indexed account, uint256 indexed programId, UFixed18 amount);\n    event FeeClaim(Token18 indexed token, UFixed18 amount);\n\n    error IncentivizerNotAllowedError(IProduct product);\n    error IncentivizerTooManyProgramsError();\n    error IncentivizerNotProgramOwnerError(IProduct product, uint256 programId);\n    error IncentivizerInvalidProgramError(IProduct product, uint256 programId);\n    error IncentivizerBatchClaimArgumentMismatchError();\n\n    function programInfos(IProduct product, uint256 programId) external view returns (ProgramInfo memory);\n    function fees(Token18 token) external view returns (UFixed18);\n    function initialize(IController controller_) external;\n    function create(IProduct product, ProgramInfo calldata info) external returns (uint256);\n    function complete(IProduct product, uint256 programId) external;\n    function sync(IOracleProvider.OracleVersion memory currentOracleVersion) external;\n    function syncAccount(address account, IOracleProvider.OracleVersion memory currentOracleVersion) external;\n    function claim(IProduct product, uint256[] calldata programIds) external;\n    function claim(IProduct[] calldata products, uint256[][] calldata programIds) external;\n    function claimFee(Token18[] calldata tokens) external;\n    function active(IProduct product) external view returns (uint256);\n    function count(IProduct product) external view returns (uint256);\n    function unclaimed(IProduct product, address account, uint256 programId) external view returns (UFixed18);\n    function available(IProduct product, uint256 programId) external view returns (UFixed18);\n    function versionStarted(IProduct product, uint256 programId) external view returns (uint256);\n    function versionComplete(IProduct product, uint256 programId) external view returns (uint256);\n    function owner(IProduct product, uint256 programId) external view returns (address);\n    function treasury(IProduct product, uint256 programId) external view returns (address);\n}\n"
    },
    "contracts/interfaces/types/PayoffDefinition.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/utils/Address.sol\";\nimport \"../../interfaces/IContractPayoffProvider.sol\";\n\n/// @dev PayoffDefinition tyoe\nstruct PayoffDefinition {\n  PayoffDefinitionLib.PayoffType payoffType;\n  PayoffDefinitionLib.PayoffDirection payoffDirection;\n  bytes30 data;\n}\nusing PayoffDefinitionLib for PayoffDefinition global;\ntype PayoffDefinitionStorage is bytes32;\nusing PayoffDefinitionStorageLib for PayoffDefinitionStorage global;\n\n/**\n * @title PayoffDefinitionLib\n * @dev Library that surfaces logic for PayoffDefinition type functionality\n * @notice Library for the PayoffDefinition type. Performs validity and price transformation\n            based on the payoff definition type.\n */\nlibrary PayoffDefinitionLib {\n  using Address for address;\n\n  error PayoffDefinitionUnsupportedTransform(PayoffType payoffType, PayoffDirection payoffDirection);\n  error PayoffDefinitionNotContract(PayoffType payoffType, bytes30 data);\n\n  /// @dev Payoff function type enum\n  enum PayoffType { PASSTHROUGH, CONTRACT }\n  enum PayoffDirection { LONG, SHORT }\n\n  /**\n   * @notice Checks validity of the payoff definition\n   * @param self a payoff definition\n   * @return Whether the payoff definition is valid for it's given type\n   */\n  function valid(PayoffDefinition memory self) internal view returns (bool) {\n    if (self.payoffType == PayoffType.CONTRACT) return address(_providerContract(self)).isContract();\n\n    // All other payoff types should have no data\n    return uint(bytes32(self.data)) == 0;\n  }\n\n  /**\n   * @notice Transforms a price based on the payoff definition\n   * @param self a payoff definition\n   * @param price raw oracle price\n   * @return Price transformed by the payoff definition function\n   */\n  function transform(\n    PayoffDefinition memory self,\n    Fixed18 price\n  ) internal view returns (Fixed18) {\n    PayoffType payoffType = self.payoffType;\n    PayoffDirection payoffDirection = self.payoffDirection;\n    Fixed18 transformedPrice;\n\n    // First get the price depending on the type\n    if (payoffType == PayoffType.PASSTHROUGH) transformedPrice = price;\n    else if (payoffType == PayoffType.CONTRACT) transformedPrice =  _payoffFromContract(self, price);\n    else revert PayoffDefinitionUnsupportedTransform(payoffType, payoffDirection);\n\n    // Then transform it depending on the direction flag\n    if (self.payoffDirection == PayoffDirection.LONG) return transformedPrice;\n    else if (self.payoffDirection == PayoffDirection.SHORT) return transformedPrice.mul(Fixed18Lib.NEG_ONE);\n    else revert PayoffDefinitionUnsupportedTransform(payoffType, payoffDirection);\n  }\n\n  /**\n   * @notice Parses the data field into an address\n   * @dev Reverts if payoffType is not CONTRACT\n   * @param self a payoff definition\n   * @return IContractPayoffProvider address\n   */\n  function _providerContract(\n    PayoffDefinition memory self\n  ) private pure returns (IContractPayoffProvider) {\n    if (self.payoffType != PayoffType.CONTRACT) revert PayoffDefinitionNotContract(self.payoffType, self.data);\n    // Shift to pull the last 20 bytes, then cast to an address\n    return IContractPayoffProvider(address(bytes20(self.data << 80)));\n  }\n\n  /**\n   * @notice Performs a price transformation by calling the underlying payoff contract\n   * @param self a payoff definition\n   * @param price raw oracle price\n   * @return Price transformed by the payoff definition function on the contract\n   */\n  function _payoffFromContract(\n    PayoffDefinition memory self,\n    Fixed18 price\n  ) private view returns (Fixed18) {\n    bytes memory ret = address(_providerContract(self)).functionStaticCall(\n      abi.encodeCall(IContractPayoffProvider.payoff, price)\n    );\n    return Fixed18.wrap(abi.decode(ret, (int256)));\n  }\n}\n\n/**\n * @title PayoffDefinitionStorageLib\n * @notice Library that surfaces storage read and writes for the PayoffDefinition type\n */\nlibrary PayoffDefinitionStorageLib {\n    function read(PayoffDefinitionStorage self) internal view returns (PayoffDefinition memory) {\n        return _storagePointer(self);\n    }\n\n    function store(PayoffDefinitionStorage self, PayoffDefinition memory value) internal {\n        PayoffDefinition storage storagePointer = _storagePointer(self);\n\n        storagePointer.payoffType = value.payoffType;\n        storagePointer.payoffDirection = value.payoffDirection;\n        storagePointer.data = value.data;\n    }\n\n    function _storagePointer(\n      PayoffDefinitionStorage self\n    ) private pure returns (PayoffDefinition storage pointer) {\n        assembly { pointer.slot := self }\n    }\n}\n"
    },
    "@equilibria/root/curve/types/JumpRateUtilizationCurve.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"../CurveMath.sol\";\nimport \"../../number/types/PackedUFixed18.sol\";\nimport \"../../number/types/PackedFixed18.sol\";\n\n/// @dev JumpRateUtilizationCurve type\nstruct JumpRateUtilizationCurve {\n    PackedFixed18 minRate;\n    PackedFixed18 maxRate;\n    PackedFixed18 targetRate;\n    PackedUFixed18 targetUtilization;\n}\nusing JumpRateUtilizationCurveLib for JumpRateUtilizationCurve global;\ntype JumpRateUtilizationCurveStorage is bytes32;\nusing JumpRateUtilizationCurveStorageLib for JumpRateUtilizationCurveStorage global;\n\n/**\n * @title JumpRateUtilizationCurveLib\n * @notice Library for the Jump Rate utilization curve type\n */\nlibrary JumpRateUtilizationCurveLib {\n    /**\n     * @notice Computes the corresponding rate for a utilization ratio\n     * @param utilization The utilization ratio\n     * @return The corresponding rate\n     */\n    function compute(JumpRateUtilizationCurve memory self, UFixed18 utilization) internal pure returns (Fixed18) {\n        UFixed18 targetUtilization = self.targetUtilization.unpack();\n        if (utilization.lt(targetUtilization)) {\n            return CurveMath.linearInterpolation(\n                UFixed18Lib.ZERO,\n                self.minRate.unpack(),\n                targetUtilization,\n                self.targetRate.unpack(),\n                utilization\n            );\n        }\n        if (utilization.lt(UFixed18Lib.ONE)) {\n            return CurveMath.linearInterpolation(\n                targetUtilization,\n                self.targetRate.unpack(),\n                UFixed18Lib.ONE,\n                self.maxRate.unpack(),\n                utilization\n            );\n        }\n        return self.maxRate.unpack();\n    }\n}\n\nlibrary JumpRateUtilizationCurveStorageLib {\n    function read(JumpRateUtilizationCurveStorage self) internal view returns (JumpRateUtilizationCurve memory) {\n        return _storagePointer(self);\n    }\n\n    function store(JumpRateUtilizationCurveStorage self, JumpRateUtilizationCurve memory value) internal {\n        JumpRateUtilizationCurve storage storagePointer = _storagePointer(self);\n\n        storagePointer.minRate = value.minRate;\n        storagePointer.maxRate = value.maxRate;\n        storagePointer.targetRate = value.targetRate;\n        storagePointer.targetUtilization = value.targetUtilization;\n    }\n\n    function _storagePointer(JumpRateUtilizationCurveStorage self)\n    private pure returns (JumpRateUtilizationCurve storage pointer) {\n        assembly { pointer.slot := self }\n    }\n}"
    },
    "contracts/interfaces/IPayoffProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/Fixed18.sol\";\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./types/PayoffDefinition.sol\";\n\ninterface IPayoffProvider {\n    error PayoffProviderInvalidOracle();\n    error PayoffProviderInvalidPayoffDefinitionError();\n\n    function oracle() external view returns (IOracleProvider);\n    function payoffDefinition() external view returns (PayoffDefinition memory);\n    function currentVersion() external view returns (IOracleProvider.OracleVersion memory);\n    function atVersion(uint256 oracleVersion) external view returns (IOracleProvider.OracleVersion memory);\n}\n"
    },
    "contracts/interfaces/IParamProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/root/curve/types/JumpRateUtilizationCurve.sol\";\n\ninterface IParamProvider {\n    event MaintenanceUpdated(UFixed18 newMaintenance);\n    event FundingFeeUpdated(UFixed18 newFundingFee);\n    event MakerFeeUpdated(UFixed18 newMakerFee);\n    event TakerFeeUpdated(UFixed18 newTakerFee);\n    event MakerLimitUpdated(UFixed18 newMakerLimit);\n    event JumpRateUtilizationCurveUpdated(\n        Fixed18 minRate,\n        Fixed18 maxRate,\n        Fixed18 targetRate,\n        UFixed18 targetUtilization\n    );\n\n    error ParamProviderInvalidMakerFee();\n    error ParamProviderInvalidTakerFee();\n    error ParamProviderInvalidFundingFee();\n    \n    function maintenance() external view returns (UFixed18);\n    function updateMaintenance(UFixed18 newMaintenance) external;\n    function fundingFee() external view returns (UFixed18);\n    function updateFundingFee(UFixed18 newFundingFee) external;\n    function makerFee() external view returns (UFixed18);\n    function updateMakerFee(UFixed18 newMakerFee) external;\n    function takerFee() external view returns (UFixed18);\n    function updateTakerFee(UFixed18 newTakerFee) external;\n    function makerLimit() external view returns (UFixed18);\n    function updateMakerLimit(UFixed18 newMakerLimit) external;\n    function utilizationCurve() external view returns (JumpRateUtilizationCurve memory);\n    function updateUtilizationCurve(JumpRateUtilizationCurve memory newUtilizationCurve) external;\n}\n"
    },
    "contracts/interfaces/types/Position.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"../IProduct.sol\";\nimport \"./Accumulator.sol\";\nimport \"./PrePosition.sol\";\nimport \"./PackedPosition.sol\";\n\n/// @dev Position type\nstruct Position {\n    /// @dev Quantity of the maker position\n    UFixed18 maker;\n    /// @dev Quantity of the taker position\n    UFixed18 taker;\n}\nusing PositionLib for Position global;\n\n/**\n * @title PositionLib\n * @notice Library that surfaces math and settlement computations for the Position type.\n * @dev Positions track the current quantity of the account's maker and taker positions respectively\n *      denominated as a unit of the product's payoff function.\n */\nlibrary PositionLib {\n    /**\n     * @notice Creates a packed position from an position\n     * @param self A position\n     * @return New packed position\n     */\n    function pack(Position memory self) internal pure returns (PackedPosition memory) {\n        return PackedPosition({maker: self.maker.pack(), taker: self.taker.pack()});\n    }\n\n    /**\n     * @notice Returns whether the position is fully empty\n     * @param self A position\n     * @return Whether the position is empty\n     */\n    function isEmpty(Position memory self) internal pure returns (bool) {\n        return self.maker.isZero() && self.taker.isZero();\n    }\n\n    /**\n     * @notice Adds position `a` and `b` together, returning the result\n     * @param a The first position to sum\n     * @param b The second position to sum\n     * @return Resulting summed position\n     */\n    function add(Position memory a, Position memory b) internal pure returns (Position memory) {\n        return Position({maker: a.maker.add(b.maker), taker: a.taker.add(b.taker)});\n    }\n\n    /**\n     * @notice Subtracts position `b` from `a`, returning the result\n     * @param a The position to subtract from\n     * @param b The position to subtract\n     * @return Resulting subtracted position\n     */\n    function sub(Position memory a, Position memory b) internal pure returns (Position memory) {\n        return Position({maker: a.maker.sub(b.maker), taker: a.taker.sub(b.taker)});\n    }\n\n    /**\n     * @notice Multiplies position `self` by accumulator `accumulator` and returns the resulting accumulator\n     * @param self The Position to operate on\n     * @param accumulator The accumulator to multiply by\n     * @return Resulting multiplied accumulator\n     */\n    function mul(Position memory self, Accumulator memory accumulator) internal pure returns (Accumulator memory) {\n        return Accumulator({\n            maker: Fixed18Lib.from(self.maker).mul(accumulator.maker),\n            taker: Fixed18Lib.from(self.taker).mul(accumulator.taker)\n        });\n    }\n\n    /**\n     * @notice Scales position `self` by fixed-decimal `scale` and returns the resulting position\n     * @param self The Position to operate on\n     * @param scale The Fixed-decimal to scale by\n     * @return Resulting scaled position\n     */\n    function mul(Position memory self, UFixed18 scale) internal pure returns (Position memory) {\n        return Position({maker: self.maker.mul(scale), taker: self.taker.mul(scale)});\n    }\n\n    /**\n     * @notice Divides position `self` by `b` and returns the resulting accumulator\n     * @param self The Position to operate on\n     * @param b The number to divide by\n     * @return Resulting divided accumulator\n     */\n    function div(Position memory self, uint256 b) internal pure returns (Accumulator memory) {\n        return Accumulator({\n            maker: Fixed18Lib.from(self.maker).div(Fixed18Lib.from(UFixed18Lib.from(b))),\n            taker: Fixed18Lib.from(self.taker).div(Fixed18Lib.from(UFixed18Lib.from(b)))\n        });\n    }\n\n    /**\n     * @notice Returns the maximum of `self`'s maker and taker values\n     * @param self The struct to operate on\n     * @return Resulting maximum value\n     */\n    function max(Position memory self) internal pure returns (UFixed18) {\n        return UFixed18Lib.max(self.maker, self.taker);\n    }\n\n    /**\n     * @notice Sums the maker and taker together from a single position\n     * @param self The struct to operate on\n     * @return The sum of its maker and taker\n     */\n    function sum(Position memory self) internal pure returns (UFixed18) {\n        return self.maker.add(self.taker);\n    }\n\n    /**\n     * @notice Computes the next position after the pending-settlement position delta is included\n     * @param self The current Position\n     * @param pre The pending-settlement position delta\n     * @return Next Position\n     */\n    function next(Position memory self, PrePosition memory pre) internal pure returns (Position memory) {\n        return sub(add(self, pre.openPosition), pre.closePosition);\n    }\n\n    /**\n     * @notice Returns the settled position at oracle version `toOracleVersion`\n     * @dev Checks if a new position is ready to be settled based on the provided `toOracleVersion`\n     *      and `pre` and returns accordingly\n     * @param self The current Position\n     * @param pre The pending-settlement position delta\n     * @param toOracleVersion The oracle version to settle to\n     * @return Settled position at oracle version\n     * @return Fee accrued from opening or closing the position\n     * @return Whether a new position was settled\n     */\n    function settled(\n        Position memory self,\n        PrePosition memory pre,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal view returns (Position memory, UFixed18, bool) {\n        return pre.canSettle(toOracleVersion) ? (next(self, pre), pre.computeFee(toOracleVersion), true) : (self, UFixed18Lib.ZERO, false);\n    }\n\n    /**\n     * @notice Returns the socialization factor for the current position\n     * @dev Socialization account for the case where `taker` > `maker` temporarily due to a liquidation\n     *      on the maker side. This dampens the taker's exposure pro-rata to ensure that the maker side\n     *      is never exposed over 1 x short.\n     * @param self The Position to operate on\n     * @return Socialization factor\n     */\n    function socializationFactor(Position memory self) internal pure returns (UFixed18) {\n        return self.taker.isZero() ? UFixed18Lib.ONE : UFixed18Lib.min(UFixed18Lib.ONE, self.maker.div(self.taker));\n    }\n}\n"
    },
    "contracts/interfaces/types/PrePosition.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./Position.sol\";\nimport \"../IProduct.sol\";\n\n/// @dev PrePosition type\nstruct PrePosition {\n    /// @dev Oracle version at which the new position delta was recorded\n    uint256 oracleVersion;\n\n    /// @dev Size of position to open at oracle version\n    Position openPosition;\n\n    /// @dev Size of position to close at oracle version\n    Position closePosition;\n}\nusing PrePositionLib for PrePosition global;\n\n/**\n * @title PrePositionLib\n * @notice Library that manages a pre-settlement position delta.\n * @dev PrePositions track the currently awaiting-settlement deltas to a settled Position. These are\n *      Primarily necessary to introduce lag into the settlement system such that oracle lag cannot be\n *      gamed to a user's advantage. When a user opens or closes a new position, it sits as a PrePosition\n *      for one oracle version until it's settle into the Position, making it then effective. PrePositions\n *      are automatically settled at the correct oracle version even if a flywheel call doesn't happen until\n *      several version into the future by using the historical version lookups in the corresponding \"Versioned\"\n *      global state types.\n */\nlibrary PrePositionLib {\n    /**\n     * @notice Returns whether there is no pending-settlement position delta\n     * @dev Can be \"empty\" even with a non-zero oracleVersion if a position is opened and\n     *      closed in the same version netting out to a zero position delta\n     * @param self The struct to operate on\n     * @return Whether the pending-settlement position delta is empty\n     */\n    function isEmpty(PrePosition memory self) internal pure returns (bool) {\n        return self.openPosition.isEmpty() && self.closePosition.isEmpty();\n    }\n\n    /**\n     * @notice Increments the maker side of the open position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The position amount to open\n     */\n    function openMake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.openPosition.maker = self.openPosition.maker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netMake(self);\n    }\n\n    /**\n     * @notice Increments the maker side of the close position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The maker position amount to close\n     */\n    function closeMake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.closePosition.maker = self.closePosition.maker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netMake(self);\n    }\n\n    /**\n     * @notice Increments the taker side of the open position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The taker position amount to open\n     */\n    function openTake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.openPosition.taker = self.openPosition.taker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netTake(self);\n    }\n\n    /**\n     * @notice Increments the taker side of the close position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The taker position amount to close\n     */\n    function closeTake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.closePosition.taker = self.closePosition.taker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netTake(self);\n    }\n\n    /**\n     * @notice Nets out the open and close on the maker side of the position delta\n     * @param self The struct to operate on\n     */\n    function _netMake(PrePosition storage self) private {\n        if (self.openPosition.maker.gt(self.closePosition.maker)) {\n            self.openPosition.maker = self.openPosition.maker.sub(self.closePosition.maker);\n            self.closePosition.maker = UFixed18Lib.ZERO;\n        } else {\n            self.closePosition.maker = self.closePosition.maker.sub(self.openPosition.maker);\n            self.openPosition.maker = UFixed18Lib.ZERO;\n        }\n    }\n\n    /**\n     * @notice Nets out the open and close on the taker side of the position delta\n     * @param self The struct to operate on\n     */\n    function _netTake(PrePosition storage self) private {\n        if (self.openPosition.taker.gt(self.closePosition.taker)) {\n            self.openPosition.taker = self.openPosition.taker.sub(self.closePosition.taker);\n            self.closePosition.taker = UFixed18Lib.ZERO;\n        } else {\n            self.closePosition.taker = self.closePosition.taker.sub(self.openPosition.taker);\n            self.openPosition.taker = UFixed18Lib.ZERO;\n        }\n    }\n\n    /**\n     * @notice Returns whether the the pending position delta can be settled at version `toOracleVersion`\n     * @dev Pending-settlement positions deltas can be settled (1) oracle version after they are recorded\n     * @param self The struct to operate on\n     * @param toOracleVersion The potential oracle version to settle\n     * @return Whether the position delta can be settled\n     */\n    function canSettle(\n        PrePosition memory self,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal pure returns (bool) {\n        return !isEmpty(self) && toOracleVersion.version > self.oracleVersion;\n    }\n\n    /**\n     * @notice Computes the fee incurred for opening or closing the pending-settlement position\n     * @dev Must be called from a valid product to get the proper fee amounts\n     * @param self The struct to operate on\n     * @param toOracleVersion The oracle version at which settlement takes place\n     * @return positionFee The maker / taker fee incurred\n     */\n    function computeFee(\n        PrePosition memory self,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal view returns (UFixed18) {\n        Position memory positionDelta = self.openPosition.add(self.closePosition);\n\n        (UFixed18 makerNotional, UFixed18 takerNotional) = (\n            Fixed18Lib.from(positionDelta.maker).mul(toOracleVersion.price).abs(),\n            Fixed18Lib.from(positionDelta.taker).mul(toOracleVersion.price).abs()\n        );\n\n        IProduct product = IProduct(address(this));\n        return makerNotional.mul(product.makerFee()).add(takerNotional.mul(product.takerFee()));\n    }\n\n    /**\n     * @notice Computes the next oracle version to settle\n     * @dev - If there is no pending-settlement position delta, returns the current oracle version\n     *      - Otherwise returns the oracle version at which the pending-settlement position delta can be first settled\n     *\n     *      Corresponds to point (b) in the Position settlement flow\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @return Next oracle version to settle\n     */\n    function settleVersion(PrePosition storage self, uint256 currentVersion) internal view returns (uint256) {\n        uint256 _oracleVersion = self.oracleVersion;\n        return _oracleVersion == 0 ? currentVersion : _oracleVersion + 1;\n    }\n}\n"
    },
    "contracts/interfaces/types/Accumulator.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/Fixed18.sol\";\nimport \"./PackedAccumulator.sol\";\n\n/// @dev Accumulator type\nstruct Accumulator {\n    /// @dev maker accumulator per share\n    Fixed18 maker;\n    /// @dev taker accumulator per share\n    Fixed18 taker;\n}\nusing AccumulatorLib for Accumulator global;\n\n/**\n * @title AccountAccumulatorLib\n * @notice Library that surfaces math operations for the Accumulator type.\n * @dev Accumulators track the cumulative change in position value over time for the maker and taker positions\n *      respectively. Account-level accumulators can then use two of these values `a` and `a'` to compute the\n *      change in position value since last sync. This change in value is then used to compute P&L and fees.\n */\nlibrary AccumulatorLib {\n    /**\n     * @notice Creates a packed accumulator from an accumulator\n     * @param self an accumulator\n     * @return New packed accumulator\n     */\n    function pack(Accumulator memory self) internal pure returns (PackedAccumulator memory) {\n        return PackedAccumulator({maker: self.maker.pack(), taker: self.taker.pack()});\n    }\n\n    /**\n     * @notice Adds two accumulators together\n     * @param a The first accumulator to sum\n     * @param b The second accumulator to sum\n     * @return The resulting summed accumulator\n     */\n    function add(Accumulator memory a, Accumulator memory b) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: a.maker.add(b.maker), taker: a.taker.add(b.taker)});\n    }\n\n    /**\n     * @notice Subtracts accumulator `b` from `a`\n     * @param a The accumulator to subtract from\n     * @param b The accumulator to subtract\n     * @return The resulting subtracted accumulator\n     */\n    function sub(Accumulator memory a, Accumulator memory b) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: a.maker.sub(b.maker), taker: a.taker.sub(b.taker)});\n    }\n\n    /**\n     * @notice Multiplies two accumulators together\n     * @param a The first accumulator to multiply\n     * @param b The second accumulator to multiply\n     * @return The resulting multiplied accumulator\n     */\n    function mul(Accumulator memory a, Accumulator memory b) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: a.maker.mul(b.maker), taker: a.taker.mul(b.taker)});\n    }\n\n    /**\n     * @notice Sums the maker and taker together from a single accumulator\n     * @param self The struct to operate on\n     * @return The sum of its maker and taker\n     */\n    function sum(Accumulator memory self) internal pure returns (Fixed18) {\n        return self.maker.add(self.taker);\n    }\n}\n"
    },
    "@equilibria/root/curve/CurveMath.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"../number/types/UFixed18.sol\";\nimport \"../number/types/Fixed18.sol\";\n\n/**\n * @title CurveMath\n * @notice Library for managing math operations for utilization curves.\n */\nlibrary CurveMath {\n    error CurveMathOutOfBoundsError();\n\n    /**\n     * @notice Computes a linear interpolation between two points\n     * @param startX First point's x-coordinate\n     * @param startY First point's y-coordinate\n     * @param endX Second point's x-coordinate\n     * @param endY Second point's y-coordinate\n     * @param targetX x-coordinate to interpolate\n     * @return y-coordinate for `targetX` along the line from (`startX`, `startY`) -> (`endX`, `endY`)\n     */\n    function linearInterpolation(\n        UFixed18 startX,\n        Fixed18 startY,\n        UFixed18 endX,\n        Fixed18 endY,\n        UFixed18 targetX\n    ) internal pure returns (Fixed18) {\n        if (targetX.lt(startX) || targetX.gt(endX)) revert CurveMathOutOfBoundsError();\n\n        UFixed18 xRange = endX.sub(startX);\n        Fixed18 yRange = endY.sub(startY);\n        UFixed18 xRatio = targetX.sub(startX).div(xRange);\n        return yRange.mul(Fixed18Lib.from(xRatio)).add(startY);\n    }\n}\n"
    },
    "@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/Fixed18.sol\";\n\ninterface IOracleProvider {\n    /// @dev A singular oracle version with its corresponding data\n    struct OracleVersion {\n        /// @dev The iterative version\n        uint256 version;\n\n        /// @dev the timestamp of the oracle update\n        uint256 timestamp;\n\n        /// @dev The oracle price of the corresponding version\n        Fixed18 price;\n    }\n\n    function sync() external returns (OracleVersion memory);\n    function currentVersion() external view returns (OracleVersion memory);\n    function atVersion(uint256 oracleVersion) external view returns (OracleVersion memory);\n}\n"
    },
    "contracts/interfaces/IContractPayoffProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/Fixed18.sol\";\n\ninterface IContractPayoffProvider {\n    function payoff(Fixed18 price) external view returns (Fixed18 payoff);\n}\n"
    },
    "contracts/interfaces/types/PackedPosition.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/PackedUFixed18.sol\";\nimport \"./Position.sol\";\n\n/// @dev PackedPosition type\nstruct PackedPosition {\n    /// @dev Quantity of the maker position\n    PackedUFixed18 maker;\n    /// @dev Quantity of the taker position\n    PackedUFixed18 taker;\n}\nusing PackedPositionLib for PackedPosition global;\n\n/**\n * @title PackedPositionLib\n * @dev A packed version of the Position which takes up a single storage slot using `PackedFixed18` values.\n * @notice Library for the packed Position type.\n */\nlibrary PackedPositionLib {\n    /**\n     * @notice Creates an position from a packed position\n     * @param self packed position\n     * @return New position\n     */\n    function unpack(PackedPosition memory self) internal pure returns (Position memory) {\n        return Position({maker: self.maker.unpack(), taker: self.taker.unpack()});\n    }\n}\n"
    },
    "contracts/interfaces/types/PackedAccumulator.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/PackedFixed18.sol\";\nimport \"./Accumulator.sol\";\n\n/// @dev PackedAccumulator type\nstruct PackedAccumulator {\n    /// @dev maker accumulator per share\n    PackedFixed18 maker;\n    /// @dev taker accumulator per share\n    PackedFixed18 taker;\n}\nusing PackedAccumulatorLib for PackedAccumulator global;\n\n/**\n * @title PackedAccumulatorLib\n * @dev A packed version of the Accumulator which takes up a single storage slot using `PackedFixed18` values.\n * @notice Library for the packed Accumulator type.\n */\nlibrary PackedAccumulatorLib {\n    /**\n     * @notice Creates an accumulator from a packed accumulator\n     * @param self packed accumulator\n     * @return New accumulator\n     */\n    function unpack(PackedAccumulator memory self) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: self.maker.unpack(), taker: self.taker.unpack()});\n    }\n}\n"
    },
    "contracts/interfaces/types/ProgramInfo.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"../IProduct.sol\";\nimport \"./Position.sol\";\nimport \"./Accumulator.sol\";\n\n/// @dev ProgramInfo type\nstruct ProgramInfo {\n    /// @dev Coordinator for this program\n    uint256 coordinatorId;\n\n    /// @dev Amount of total maker and taker rewards\n    Position amount;\n\n    /// @dev start timestamp of the program\n    uint256 start;\n\n    /// @dev duration of the program (in seconds)\n    uint256 duration;\n\n    /**\n     * @dev Reward ERC20 token contract\n     * @notice Perennial does not support non-standard ERC20s as reward tokens for incentive programs, including,\n                but not limited to: fee on transfer and rebase tokens. Using such a non-standard token will likely\n                result in loss of funds.\n     */\n    Token18 token;\n}\nusing ProgramInfoLib for ProgramInfo global;\n\n/**\n * @title ProgramInfoLib\n * @notice Library that snapshots the static information for a single program.\n * @dev This information does not change during the operation of a program.\n */\nlibrary ProgramInfoLib {\n    uint256 private constant MIN_DURATION = 1 days;\n    uint256 private constant MAX_DURATION = 2 * 365 days;\n\n    error ProgramInvalidStartError();\n    error ProgramInvalidDurationError();\n\n    /**\n     * @notice Validates and creates a new Program\n     * @dev Reverts for invalid programInfos\n     * @param programInfo Un-sanitized static program information\n     */\n    function validate(ProgramInfo memory programInfo) internal view {\n        if (isStarted(programInfo, block.timestamp)) revert ProgramInvalidStartError();\n        if (programInfo.duration < MIN_DURATION || programInfo.duration > MAX_DURATION) revert ProgramInvalidDurationError();\n    }\n\n    /**\n     * @notice Computes a new program info with the fee taken out of the amount\n     * @param programInfo Original program info\n     * @param incentivizationFee The incentivization fee\n     * @return New program info\n     * @return Fee amount\n     */\n    function deductFee(ProgramInfo memory programInfo, UFixed18 incentivizationFee)\n    internal pure returns (ProgramInfo memory, UFixed18) {\n        Position memory newProgramAmount = programInfo.amount.mul(UFixed18Lib.ONE.sub(incentivizationFee));\n        UFixed18 programFeeAmount = programInfo.amount.sub(newProgramAmount).sum();\n        programInfo.amount = newProgramAmount;\n        return (programInfo, programFeeAmount);\n    }\n\n    /**\n     * @notice Returns the maker and taker amounts per position share\n     * @param self The ProgramInfo to operate on\n     * @return programFee Amounts per share\n     */\n    function amountPerShare(ProgramInfo memory self) internal pure returns (Accumulator memory) {\n        return self.amount.div(self.duration);\n    }\n\n    /**\n     * @notice Returns whether the program has started by timestamp `timestamp`\n     * @param self The ProgramInfo to operate on\n     * @param timestamp Timestamp to check for\n     * @return Whether the program has started\n     */\n    function isStarted(ProgramInfo memory self, uint256 timestamp) internal pure returns (bool) {\n        return timestamp >= self.start;\n    }\n\n    /**\n     * @notice Returns whether the program is completed by timestamp `timestamp`\n     * @param self The ProgramInfo to operate on\n     * @param timestamp Timestamp to check for\n     * @return Whether the program is completed\n     */\n    function isComplete(ProgramInfo memory self, uint256 timestamp) internal pure returns (bool) {\n        return timestamp >= (self.start + self.duration);\n    }\n}\n"
    },
    "contracts/product/UParamProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/control/unstructured/UInitializable.sol\";\nimport \"../controller/UControllerProvider.sol\";\nimport \"../interfaces/IParamProvider.sol\";\nimport \"../interfaces/IProduct.sol\";\n\nabstract contract UParamProvider is IParamProvider, UControllerProvider {\n    /**\n     * @notice Initializes the contract state\n     * @param maintenance_ product maintenance ratio\n     * @param fundingFee_ product funding fee\n     * @param makerFee_ product maker fee\n     * @param takerFee_ product taker fee\n     * @param makerLimit_ product maker limit\n     * @param utilizationCurve_ utulization curve definition\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function __UParamProvider__initialize(\n        UFixed18 maintenance_,\n        UFixed18 fundingFee_,\n        UFixed18 makerFee_,\n        UFixed18 takerFee_,\n        UFixed18 makerLimit_,\n        JumpRateUtilizationCurve memory utilizationCurve_\n    ) internal onlyInitializer {\n        _updateMaintenance(maintenance_);\n        _updateFundingFee(fundingFee_);\n        _updateMakerFee(makerFee_);\n        _updateTakerFee(takerFee_);\n        _updateMakerLimit(makerLimit_);\n        _updateUtilizationCurve(utilizationCurve_);\n    }\n\n    /// @dev Only allow the Product's coordinator owner to call\n    modifier onlyProductOwner {\n        uint256 coordinatorId = controller().coordinatorFor(IProduct(address(this)));\n        if (controller().owner(coordinatorId) != msg.sender) revert NotOwnerError(coordinatorId);\n\n        _;\n    }\n\n    /// @dev The maintenance value\n    UFixed18Storage private constant _maintenance = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.UParamProvider.maintenance\"));\n    function maintenance() public view returns (UFixed18) { return _maintenance.read(); }\n\n    /// @dev The funding fee value\n    UFixed18Storage private constant _fundingFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.UParamProvider.fundingFee\"));\n    function fundingFee() public view returns (UFixed18) { return _fundingFee.read(); }\n\n    /// @dev The maker fee value\n    UFixed18Storage private constant _makerFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.UParamProvider.makerFee\"));\n    function makerFee() public view returns (UFixed18) { return _makerFee.read(); }\n\n    /// @dev The taker fee value\n    UFixed18Storage private constant _takerFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.UParamProvider.takerFee\"));\n    function takerFee() public view returns (UFixed18) { return _takerFee.read(); }\n\n    /// @dev The maker limit value\n    UFixed18Storage private constant _makerLimit = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.UParamProvider.makerLimit\"));\n    function makerLimit() public view returns (UFixed18) { return _makerLimit.read(); }\n\n    /// @dev The JumpRateUtilizationCurve params\n    JumpRateUtilizationCurveStorage private constant _utilizationCurve =\n        JumpRateUtilizationCurveStorage.wrap(keccak256(\"equilibria.perennial.UParamProvider.jumpRateUtilizationCurve\"));\n    function utilizationCurve() public view returns (JumpRateUtilizationCurve memory) { return _utilizationCurve.read(); }\n\n    /**\n     * @notice Updates the maintenance to `newMaintenance`\n     * @param newMaintenance new maintenance value\n     */\n    function _updateMaintenance(UFixed18 newMaintenance) private {\n        _maintenance.store(newMaintenance);\n        emit MaintenanceUpdated(newMaintenance);\n    }\n\n    /**\n     * @notice Updates the maintenance to `newMaintenance`\n     * @dev only callable by product owner\n     * @param newMaintenance new maintenance value\n     */\n    function updateMaintenance(UFixed18 newMaintenance) external onlyProductOwner {\n        _updateMaintenance(newMaintenance);\n    }\n\n    /**\n     * @notice Updates the funding fee to `newFundingFee`\n     * @param newFundingFee new funding fee value\n     */\n    function _updateFundingFee(UFixed18 newFundingFee) private {\n        if (newFundingFee.gt(UFixed18Lib.ONE)) revert ParamProviderInvalidFundingFee();\n        _fundingFee.store(newFundingFee);\n        emit FundingFeeUpdated(newFundingFee);\n    }\n\n    /**\n     * @notice Updates the funding fee to `newFundingFee`\n     * @dev only callable by product owner\n     * @param newFundingFee new funding fee value\n     */\n    function updateFundingFee(UFixed18 newFundingFee) external onlyProductOwner {\n        _updateFundingFee(newFundingFee);\n    }\n\n    /**\n     * @notice Updates the maker fee to `newMakerFee`\n     * @param newMakerFee new maker fee value\n     */\n    function _updateMakerFee(UFixed18 newMakerFee) private {\n        if (newMakerFee.gt(UFixed18Lib.ZERO)) revert ParamProviderInvalidMakerFee();\n        _makerFee.store(newMakerFee);\n        emit MakerFeeUpdated(newMakerFee);\n    }\n\n    /**\n     * @notice Updates the maker fee to `newMakerFee`\n     * @dev only callable by product owner\n     * @param newMakerFee new maker fee value\n     */\n    function updateMakerFee(UFixed18 newMakerFee) external onlyProductOwner {\n        _updateMakerFee(newMakerFee);\n    }\n\n    /**\n     * @notice Updates the taker fee to `newTakerFee`\n     * @param newTakerFee new taker fee value\n     */\n    function _updateTakerFee(UFixed18 newTakerFee) private {\n        if (newTakerFee.gt(UFixed18Lib.ZERO)) revert ParamProviderInvalidTakerFee();\n        _takerFee.store(newTakerFee);\n        emit TakerFeeUpdated(newTakerFee);\n    }\n\n    /**\n     * @notice Updates the taker fee to `newTakerFee`\n     * @dev only callable by product owner\n     * @param newTakerFee new taker fee value\n     */\n    function updateTakerFee(UFixed18 newTakerFee) external onlyProductOwner {\n        _updateTakerFee(newTakerFee);\n    }\n\n    /**\n     * @notice Updates the maker limit to `newMakerLimit`\n     * @param newMakerLimit new maker limit value\n     */\n    function _updateMakerLimit(UFixed18 newMakerLimit) private {\n        _makerLimit.store(newMakerLimit);\n        emit MakerLimitUpdated(newMakerLimit);\n    }\n\n    /**\n     * @notice Updates the maker limit to `newMakerLimit`\n     * @dev only callable by product owner\n     * @param newMakerLimit new maker limit value\n     */\n    function updateMakerLimit(UFixed18 newMakerLimit) external onlyProductOwner {\n        _updateMakerLimit(newMakerLimit);\n    }\n\n    /**\n     * @notice Updates the utilization curve to `newUtilizationCurve`\n     * @param newUtilizationCurve new utilization curve value\n     */\n    function _updateUtilizationCurve(JumpRateUtilizationCurve memory newUtilizationCurve) private {\n        _utilizationCurve.store(newUtilizationCurve);\n        emit JumpRateUtilizationCurveUpdated(\n            newUtilizationCurve.minRate.unpack(),\n            newUtilizationCurve.maxRate.unpack(),\n            newUtilizationCurve.targetRate.unpack(),\n            newUtilizationCurve.targetUtilization.unpack()\n        );\n    }\n\n    /**\n     * @notice Updates the utilization curve to `newUtilizationCurve`\n     * @dev only callable by product owner\n     * @param newUtilizationCurve new utilization curve value\n     */\n    function updateUtilizationCurve(JumpRateUtilizationCurve calldata newUtilizationCurve) external onlyProductOwner {\n        _updateUtilizationCurve(newUtilizationCurve);\n    }\n}\n"
    },
    "contracts/product/types/accumulator/VersionedAccumulator.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../../../interfaces/IProduct.sol\";\nimport \"../../../interfaces/types/Accumulator.sol\";\nimport \"../position/VersionedPosition.sol\";\n\n/// @dev VersionedAccumulator type\nstruct VersionedAccumulator {\n    /// @dev Latest synced oracle version\n    uint256 latestVersion;\n\n    /// @dev Mapping of accumulator value at each settled oracle version\n    mapping(uint256 => PackedAccumulator) _valueAtVersion;\n\n    /// @dev Mapping of accumulator share at each settled oracle version\n    mapping(uint256 => PackedAccumulator) _shareAtVersion;\n}\nusing VersionedAccumulatorLib for VersionedAccumulator global;\n\n/**\n * @title VersionedAccumulatorLib\n * @notice Library that manages global versioned accumulator state.\n * @dev Manages two accumulators: value and share. The value accumulator measures the change in position value\n *      over time. The share accumulator measures the change in liquidity ownership over time (for tracking\n *      incentivization rewards).\n *\n *      Both accumulators are stamped for historical lookup anytime there is a global settlement, which services\n *      the delayed-position accounting. It is not guaranteed that every version will have a value stamped, but\n *      only versions when a settlement occurred are needed for this historical computation.\n */\nlibrary VersionedAccumulatorLib {\n    /**\n     * @notice Returns the stamped value accumulator at `oracleVersion`\n     * @param self The struct to operate on\n     * @param oracleVersion The oracle version to retrieve the value at\n     * @return The stamped value accumulator at the requested version\n     */\n    function valueAtVersion(VersionedAccumulator storage self, uint256 oracleVersion) internal view returns (Accumulator memory) {\n        return self._valueAtVersion[oracleVersion].unpack();\n    }\n\n    /**\n     * @notice Returns the stamped share accumulator at `oracleVersion`\n     * @param self The struct to operate on\n     * @param oracleVersion The oracle version to retrieve the share at\n     * @return The stamped share accumulator at the requested version\n     */\n    function shareAtVersion(VersionedAccumulator storage self, uint256 oracleVersion) internal view returns (Accumulator memory) {\n        return self._shareAtVersion[oracleVersion].unpack();\n    }\n\n    /**\n     * @notice Globally accumulates all value (position + funding) and share since last oracle update\n     * @param self The struct to operate on\n     * @param fundingFee The funding fee rate for the product\n     * @param position Pointer to global position\n     * @param latestOracleVersion The oracle version to accumulate from\n     * @param toOracleVersion The oracle version to accumulate to\n     * @return accumulatedFee The total fee accrued from accumulation\n     */\n    function accumulate(\n        VersionedAccumulator storage self,\n        UFixed18 fundingFee,\n        VersionedPosition storage position,\n        IOracleProvider.OracleVersion memory latestOracleVersion,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal returns (UFixed18 accumulatedFee) {\n        Position memory latestPosition = position.positionAtVersion(latestOracleVersion.version);\n\n        // accumulate funding\n        Accumulator memory accumulatedPosition;\n        (accumulatedPosition, accumulatedFee) =\n            _accumulateFunding(fundingFee, latestPosition, latestOracleVersion, toOracleVersion);\n\n        // accumulate position\n        accumulatedPosition = accumulatedPosition.add(\n            _accumulatePosition(latestPosition, latestOracleVersion, toOracleVersion));\n\n        // accumulate share\n        Accumulator memory accumulatedShare =\n            _accumulateShare(latestPosition, latestOracleVersion, toOracleVersion);\n\n        // save update\n        self._valueAtVersion[toOracleVersion.version] = valueAtVersion(self, latestOracleVersion.version)\n            .add(accumulatedPosition)\n            .pack();\n        self._shareAtVersion[toOracleVersion.version] = shareAtVersion(self, latestOracleVersion.version)\n            .add(accumulatedShare)\n            .pack();\n        self.latestVersion = toOracleVersion.version;\n    }\n\n    /**\n     * @notice Globally accumulates all funding since last oracle update\n     * @dev If an oracle version is skipped due to no pre positions, funding will continue to be\n     *      pegged to the price of the last snapshotted oracleVersion until a new one is accumulated.\n     *      This is an acceptable approximation.\n     * @param fundingFee The funding fee rate for the product\n     * @param latestPosition The latest global position\n     * @param latestOracleVersion The oracle version to accumulate from\n     * @param toOracleVersion The oracle version to accumulate to\n     * @return accumulatedFunding The total amount accumulated from funding\n     * @return accumulatedFee The total fee accrued from funding accumulation\n     */\n    function _accumulateFunding(\n        UFixed18 fundingFee,\n        Position memory latestPosition,\n        IOracleProvider.OracleVersion memory latestOracleVersion,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) private view returns (Accumulator memory accumulatedFunding, UFixed18 accumulatedFee) {\n        if (_product().closed()) return (Accumulator(Fixed18Lib.ZERO, Fixed18Lib.ZERO), UFixed18Lib.ZERO);\n        if (latestPosition.taker.isZero()) return (Accumulator(Fixed18Lib.ZERO, Fixed18Lib.ZERO), UFixed18Lib.ZERO);\n        if (latestPosition.maker.isZero()) return (Accumulator(Fixed18Lib.ZERO, Fixed18Lib.ZERO), UFixed18Lib.ZERO);\n\n        uint256 elapsed = toOracleVersion.timestamp - latestOracleVersion.timestamp;\n\n        UFixed18 takerNotional = Fixed18Lib.from(latestPosition.taker).mul(latestOracleVersion.price).abs();\n        UFixed18 socializedNotional = takerNotional.mul(latestPosition.socializationFactor());\n\n        Fixed18 rateAccumulated = _product().rate(latestPosition)\n            .mul(Fixed18Lib.from(UFixed18Lib.from(elapsed)));\n        Fixed18 fundingAccumulated = rateAccumulated.mul(Fixed18Lib.from(socializedNotional));\n        accumulatedFee = fundingAccumulated.abs().mul(fundingFee);\n\n        Fixed18 fundingAccumulatedWithoutFee = Fixed18Lib.from(\n            fundingAccumulated.sign(),\n            fundingAccumulated.abs().sub(accumulatedFee)\n        );\n\n        bool makerPaysFunding = fundingAccumulated.sign() < 0;\n        accumulatedFunding.maker = (makerPaysFunding ? fundingAccumulated : fundingAccumulatedWithoutFee)\n            .div(Fixed18Lib.from(latestPosition.maker));\n        accumulatedFunding.taker = (makerPaysFunding ? fundingAccumulatedWithoutFee : fundingAccumulated)\n            .div(Fixed18Lib.from(latestPosition.taker)).mul(Fixed18Lib.NEG_ONE);\n    }\n\n    /**\n     * @notice Globally accumulates position PNL since last oracle update\n     * @param latestPosition The latest global position\n     * @param latestOracleVersion The oracle version to accumulate from\n     * @param toOracleVersion The oracle version to accumulate to\n     * @return accumulatedPosition The total amount accumulated from position PNL\n     */\n    function _accumulatePosition(\n        Position memory latestPosition,\n        IOracleProvider.OracleVersion memory latestOracleVersion,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) private view returns (Accumulator memory accumulatedPosition) {\n        if (_product().closed()) return Accumulator(Fixed18Lib.ZERO, Fixed18Lib.ZERO);\n        if (latestPosition.taker.isZero()) return Accumulator(Fixed18Lib.ZERO, Fixed18Lib.ZERO);\n        if (latestPosition.maker.isZero()) return Accumulator(Fixed18Lib.ZERO, Fixed18Lib.ZERO);\n\n        Fixed18 oracleDelta = toOracleVersion.price.sub(latestOracleVersion.price);\n        Fixed18 totalTakerDelta = oracleDelta.mul(Fixed18Lib.from(latestPosition.taker));\n        Fixed18 socializedTakerDelta = totalTakerDelta.mul(Fixed18Lib.from(latestPosition.socializationFactor()));\n\n        accumulatedPosition.maker = socializedTakerDelta.div(Fixed18Lib.from(latestPosition.maker)).mul(Fixed18Lib.NEG_ONE);\n        accumulatedPosition.taker = socializedTakerDelta.div(Fixed18Lib.from(latestPosition.taker));\n    }\n\n    /**\n     * @notice Globally accumulates position's share of the total market since last oracle update\n     * @dev This is used to compute incentivization rewards based on market participation\n     * @param latestPosition The latest global position\n     * @param latestOracleVersion The oracle version to accumulate from\n     * @param toOracleVersion The oracle version to accumulate to\n     * @return accumulatedShare The total share amount accumulated per position\n     */\n    function _accumulateShare(\n        Position memory latestPosition,\n        IOracleProvider.OracleVersion memory latestOracleVersion,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) private pure returns (Accumulator memory accumulatedShare) {\n        uint256 elapsed = toOracleVersion.timestamp - latestOracleVersion.timestamp;\n\n        accumulatedShare.maker = latestPosition.maker.isZero() ?\n            Fixed18Lib.ZERO :\n            Fixed18Lib.from(UFixed18Lib.from(elapsed).div(latestPosition.maker));\n        accumulatedShare.taker = latestPosition.taker.isZero() ?\n            Fixed18Lib.ZERO :\n            Fixed18Lib.from(UFixed18Lib.from(elapsed).div(latestPosition.taker));\n    }\n\n    function _product() private view returns (IProduct) {\n        return IProduct(address(this));\n    }\n}\n"
    },
    "contracts/product/types/position/VersionedPosition.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../../../interfaces/types/PrePosition.sol\";\nimport \"../../../interfaces/types/PackedPosition.sol\";\n\n//// @dev VersionedPosition type\nstruct VersionedPosition {\n    /// @dev Mapping of global position at each version\n    mapping(uint256 => PackedPosition) _positionAtVersion;\n\n    /// @dev Current global pending-settlement position delta\n    PrePosition pre;\n}\nusing VersionedPositionLib for VersionedPosition global;\n\n/**\n * @title VersionedPositionLib\n * @notice Library that manages global position state.\n * @dev Global position state is used to compute utilization rate and socialization, and to account for and\n *      distribute fees globally.\n *\n *      Positions are stamped for historical lookup anytime there is a global settlement, which services\n *      the delayed-position accounting. It is not guaranteed that every version will have a value stamped, but\n *      only versions when a settlement occurred are needed for this historical computation.\n */\nlibrary VersionedPositionLib {\n    /**\n     * @notice Returns the current global position\n     * @return Current global position\n     */\n    function positionAtVersion(VersionedPosition storage self, uint256 oracleVersion) internal view returns (Position memory) {\n        return self._positionAtVersion[oracleVersion].unpack();\n    }\n\n    /**\n     * @notice Settled the global position to oracle version `toOracleVersion`\n     * @param self The struct to operate on\n     * @param latestVersion The latest settled oracle version\n     * @param toOracleVersion The oracle version to settle to\n     * @return positionFee The fee accrued from opening or closing a new position\n     */\n    function settle(\n        VersionedPosition storage self,\n        uint256 latestVersion,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal returns (UFixed18) {\n        (Position memory newPosition, UFixed18 positionFee, bool settled) =\n            positionAtVersion(self, latestVersion).settled(self.pre, toOracleVersion);\n\n        self._positionAtVersion[toOracleVersion.version] = newPosition.pack();\n        if (settled) delete self.pre;\n\n        return positionFee;\n    }\n}\n"
    },
    "contracts/test/TestnetProductProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/curve/types/JumpRateUtilizationCurve.sol\";\nimport \"../interfaces/IContractPayoffProvider.sol\";\n\ncontract TestnetContractPayoffProvider is IContractPayoffProvider {\n    function payoff(Fixed18 price) public pure returns (Fixed18) {\n        return price.mul(price);\n    }\n}\n"
    },
    "contracts/product/types/accumulator/AccountAccumulator.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../../../interfaces/types/Accumulator.sol\";\nimport \"../position/AccountPosition.sol\";\nimport \"./VersionedAccumulator.sol\";\n\n/// @dev AccountAccumulator type\nstruct AccountAccumulator {\n    /// @dev latest version that the account was synced too\n    uint256 latestVersion;\n}\nusing AccountAccumulatorLib for AccountAccumulator global;\n\n/**\n * @title AccountAccumulatorLib\n * @notice Library that manages syncing an account-level accumulator.\n */\nlibrary AccountAccumulatorLib {\n    /**\n     * @notice Syncs the account to oracle version `versionTo`\n     * @param self The struct to operate on\n     * @param global Pointer to global accumulator\n     * @param position Pointer to global position\n     * @param versionTo Oracle version to sync account to\n     * @return value The value accumulated sync last sync\n     */\n    function syncTo(\n        AccountAccumulator storage self,\n        VersionedAccumulator storage global,\n        AccountPosition storage position,\n        uint256 versionTo\n    ) internal returns (Accumulator memory value) {\n        Accumulator memory valueAccumulated = global.valueAtVersion(versionTo)\n            .sub(global.valueAtVersion(self.latestVersion));\n        value = position.position.mul(valueAccumulated);\n        self.latestVersion = versionTo;\n    }\n}\n"
    },
    "contracts/product/types/position/AccountPosition.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../../../interfaces/IProduct.sol\";\nimport \"../../../interfaces/types/PrePosition.sol\";\n\n/// @dev AccountPosition type\nstruct AccountPosition {\n    /// @dev The current settled position of the account\n    Position position;\n\n    /// @dev The current position delta pending-settlement\n    PrePosition pre;\n\n    /// @dev Whether the account is currently locked for liquidation\n    bool liquidation;\n}\nusing AccountPositionLib for AccountPosition global;\n\n/**\n * @title AccountPositionLib\n * @notice Library that manages an account-level position.\n */\nlibrary AccountPositionLib {\n    /**\n     * @notice Settled the account's position to oracle version `toOracleVersion`\n     * @param self The struct to operate on\n     * @param toOracleVersion The oracle version to accumulate to\n     * @return positionFee The fee accrued from opening or closing a new position\n     */\n    function settle(\n        AccountPosition storage self,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal returns (UFixed18 positionFee) {\n        bool settled;\n        (self.position, positionFee, settled) = self.position.settled(self.pre, toOracleVersion);\n        if (settled) {\n            delete self.pre;\n            self.liquidation = false;\n        }\n    }\n\n    /**\n     * @notice Returns the current maintenance requirement for the account\n     * @dev Must be called from a valid product to get the proper maintenance value\n     * @param self The struct to operate on\n     * @return Current maintenance requirement for the account\n     */\n    function maintenance(AccountPosition storage self) internal view returns (UFixed18) {\n        if (self.liquidation) return UFixed18Lib.ZERO;\n        return _maintenance(self.position);\n    }\n\n    /**\n     * @notice Returns the maintenance requirement after the next oracle version settlement\n     * @dev Includes the current pending-settlement position delta, assumes no price change\n     * @param self The struct to operate on\n     * @return Next maintenance requirement for the account\n     */\n    function maintenanceNext(AccountPosition storage self) internal view returns (UFixed18) {\n        return _maintenance(self.position.next(self.pre));\n    }\n\n    /**\n     * @notice Returns the maintenance requirement for a given `position`\n     * @dev Internal helper\n     * @param position The position to compete the maintenance requirement for\n     * @return Next maintenance requirement for the account\n     */\n    function _maintenance(Position memory position) private view returns (UFixed18) {\n        IProduct product = IProduct(address(this));\n        Fixed18 oraclePrice = product.currentVersion().price;\n        UFixed18 notionalMax = Fixed18Lib.from(position.max()).mul(oraclePrice).abs();\n        return notionalMax.mul(product.maintenance());\n    }\n\n    /**\n     * @notice Returns whether an account is completely closed, i.e. no position or pre-position\n     * @param self The struct to operate on\n     * @return Whether the account is closed\n     */\n    function isClosed(AccountPosition memory self) internal pure returns (bool) {\n        return self.pre.isEmpty() && self.position.isEmpty();\n    }\n\n    /**\n     * @notice Returns whether an account has opened position on both sides of the market (maker vs taker)\n     * @dev Used to verify the invariant that a single account can only have a position on one side of the\n     *      market at a time\n     * @param self The struct to operate on\n     * @return Whether the account is currently doubled sided\n     */\n    function isDoubleSided(AccountPosition storage self) internal view returns (bool) {\n        bool makerEmpty = self.position.maker.isZero() && self.pre.openPosition.maker.isZero() && self.pre.closePosition.maker.isZero();\n        bool takerEmpty = self.position.taker.isZero() && self.pre.openPosition.taker.isZero() && self.pre.closePosition.taker.isZero();\n\n        return !makerEmpty && !takerEmpty;\n    }\n\n    /**\n     * @notice Returns whether the account's pending-settlement delta closes more position than is open\n     * @dev Used to verify the invariant that an account cannot settle into having a negative position\n     * @param self The struct to operate on\n     * @return Whether the account is currently over closed\n     */\n    function isOverClosed(AccountPosition storage self) internal view returns (bool) {\n        Position memory nextOpen = self.position.add(self.pre.openPosition);\n\n        return  self.pre.closePosition.maker.gt(nextOpen.maker) || self.pre.closePosition.taker.gt(nextOpen.taker);\n    }\n}\n"
    },
    "contracts/product/UPayoffProvider.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/control/unstructured/UInitializable.sol\";\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"@equilibria/root/storage/UStorage.sol\";\nimport \"../interfaces/IPayoffProvider.sol\";\nimport \"../interfaces/types/PayoffDefinition.sol\";\n\n/**\n * @title UPayoffProvider\n * @notice Library for manage storing, surfacing, and upgrading a payoff provider.\n * @dev Uses an unstructured storage pattern to store the oracle address and payoff definition which allows this\n        provider to be safely used with upgradeable contracts.\n */\nabstract contract UPayoffProvider is IPayoffProvider, UInitializable {\n    /// @dev The oracle contract address\n    AddressStorage private constant _oracle =\n        AddressStorage.wrap(keccak256(\"equilibria.perennial.UPayoffProvider.oracle\"));\n    function oracle() public view returns (IOracleProvider) { return IOracleProvider(_oracle.read()); }\n\n    /// @dev Payoff definition struct\n    PayoffDefinitionStorage private constant _payoffDefinition =\n        PayoffDefinitionStorage.wrap(keccak256(\"equilibria.perennial.UPayoffProvider.payoffDefinition\"));\n    function payoffDefinition() public view returns (PayoffDefinition memory) { return _payoffDefinition.read(); }\n\n    /**\n     * @notice Initializes the contract state\n     * @param oracle_ Oracle address\n     * @param payoffDefinition_ Payoff provider\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function __UPayoffProvider__initialize(IOracleProvider oracle_, PayoffDefinition calldata payoffDefinition_) internal onlyInitializer {\n        if (!Address.isContract(address(oracle_))) revert PayoffProviderInvalidOracle();\n        _oracle.store(address(oracle_));\n\n        if (!payoffDefinition_.valid()) revert PayoffProviderInvalidPayoffDefinitionError();\n        _payoffDefinition.store(payoffDefinition_);\n    }\n\n    /**\n     * @notice Returns the current oracle version transformed by the payoff definition\n     * @return Current oracle version transformed by the payoff definition\n     */\n    function currentVersion() public view returns (IOracleProvider.OracleVersion memory) {\n        return _transform(oracle().currentVersion());\n    }\n\n    /**\n     * @notice Returns the oracle version at `oracleVersion` transformed by the payoff definition\n     * @param oracleVersion Oracle version to return for\n     * @return Oracle version at `oracleVersion` with price transformed by payoff function\n     */\n    function atVersion(uint256 oracleVersion) public view returns (IOracleProvider.OracleVersion memory) {\n        return _transform(oracle().atVersion(oracleVersion));\n    }\n\n    /**\n     * @notice Yook to call sync() on the oracle provider and transform the resulting oracle version\n     */\n    function _sync() internal returns (IOracleProvider.OracleVersion memory) {\n        return _transform(oracle().sync());\n    }\n\n    /**\n     * @notice Returns the transformed oracle version\n     * @param oracleVersion Oracle version to transform\n     * @return Transformed oracle version\n     */\n    function _transform(IOracleProvider.OracleVersion memory oracleVersion)\n    internal view virtual returns (IOracleProvider.OracleVersion memory) {\n        oracleVersion.price = payoffDefinition().transform(oracleVersion.price);\n        return oracleVersion;\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../../access/Ownable.sol\";\nimport \"../../utils/Address.sol\";\n\n/**\n * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their\n * implementation contract, which is where they will delegate all function calls.\n *\n * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.\n */\ncontract UpgradeableBeacon is IBeacon, Ownable {\n    address private _implementation;\n\n    /**\n     * @dev Emitted when the implementation returned by the beacon is changed.\n     */\n    event Upgraded(address indexed implementation);\n\n    /**\n     * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the\n     * beacon.\n     */\n    constructor(address implementation_) {\n        _setImplementation(implementation_);\n    }\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function implementation() public view virtual override returns (address) {\n        return _implementation;\n    }\n\n    /**\n     * @dev Upgrades the beacon to a new implementation.\n     *\n     * Emits an {Upgraded} event.\n     *\n     * Requirements:\n     *\n     * - msg.sender must be the owner of the contract.\n     * - `newImplementation` must be a contract.\n     */\n    function upgradeTo(address newImplementation) public virtual onlyOwner {\n        _setImplementation(newImplementation);\n        emit Upgraded(newImplementation);\n    }\n\n    /**\n     * @dev Sets the implementation contract address for this beacon\n     *\n     * Requirements:\n     *\n     * - `newImplementation` must be a contract.\n     */\n    function _setImplementation(address newImplementation) private {\n        require(Address.isContract(newImplementation), \"UpgradeableBeacon: implementation is not a contract\");\n        _implementation = newImplementation;\n    }\n}\n"
    },
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../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 * By default, the owner account will be the one that deploys the contract. This\n * can 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    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _transferOwnership(_msgSender());\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 called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing 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        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\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"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\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"
    },
    "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./TransparentUpgradeableProxy.sol\";\nimport \"../../access/Ownable.sol\";\n\n/**\n * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an\n * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.\n */\ncontract ProxyAdmin is Ownable {\n    /**\n     * @dev Returns the current implementation of `proxy`.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function getProxyImplementation(TransparentUpgradeableProxy proxy) public view virtual returns (address) {\n        // We need to manually run the static call since the getter cannot be flagged as view\n        // bytes4(keccak256(\"implementation()\")) == 0x5c60da1b\n        (bool success, bytes memory returndata) = address(proxy).staticcall(hex\"5c60da1b\");\n        require(success);\n        return abi.decode(returndata, (address));\n    }\n\n    /**\n     * @dev Returns the current admin of `proxy`.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function getProxyAdmin(TransparentUpgradeableProxy proxy) public view virtual returns (address) {\n        // We need to manually run the static call since the getter cannot be flagged as view\n        // bytes4(keccak256(\"admin()\")) == 0xf851a440\n        (bool success, bytes memory returndata) = address(proxy).staticcall(hex\"f851a440\");\n        require(success);\n        return abi.decode(returndata, (address));\n    }\n\n    /**\n     * @dev Changes the admin of `proxy` to `newAdmin`.\n     *\n     * Requirements:\n     *\n     * - This contract must be the current admin of `proxy`.\n     */\n    function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner {\n        proxy.changeAdmin(newAdmin);\n    }\n\n    /**\n     * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner {\n        proxy.upgradeTo(implementation);\n    }\n\n    /**\n     * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See\n     * {TransparentUpgradeableProxy-upgradeToAndCall}.\n     *\n     * Requirements:\n     *\n     * - This contract must be the admin of `proxy`.\n     */\n    function upgradeAndCall(\n        TransparentUpgradeableProxy proxy,\n        address implementation,\n        bytes memory data\n    ) public payable virtual onlyOwner {\n        proxy.upgradeToAndCall{value: msg.value}(implementation, data);\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/transparent/TransparentUpgradeableProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC1967/ERC1967Proxy.sol\";\n\n/**\n * @dev This contract implements a proxy that is upgradeable by an admin.\n *\n * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector\n * clashing], which can potentially be used in an attack, this contract uses the\n * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two\n * things that go hand in hand:\n *\n * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if\n * that call matches one of the admin functions exposed by the proxy itself.\n * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the\n * implementation. If the admin tries to call a function on the implementation it will fail with an error that says\n * \"admin cannot fallback to proxy target\".\n *\n * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing\n * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due\n * to sudden errors when trying to call a function from the proxy implementation.\n *\n * Our recommendation is for the dedicated account to be an instance of the {ProxyAdmin} contract. If set up this way,\n * you should think of the `ProxyAdmin` instance as the real administrative interface of your proxy.\n */\ncontract TransparentUpgradeableProxy is ERC1967Proxy {\n    /**\n     * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and\n     * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}.\n     */\n    constructor(\n        address _logic,\n        address admin_,\n        bytes memory _data\n    ) payable ERC1967Proxy(_logic, _data) {\n        assert(_ADMIN_SLOT == bytes32(uint256(keccak256(\"eip1967.proxy.admin\")) - 1));\n        _changeAdmin(admin_);\n    }\n\n    /**\n     * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin.\n     */\n    modifier ifAdmin() {\n        if (msg.sender == _getAdmin()) {\n            _;\n        } else {\n            _fallback();\n        }\n    }\n\n    /**\n     * @dev Returns the current admin.\n     *\n     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyAdmin}.\n     *\n     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\n     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n     * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`\n     */\n    function admin() external ifAdmin returns (address admin_) {\n        admin_ = _getAdmin();\n    }\n\n    /**\n     * @dev Returns the current implementation.\n     *\n     * NOTE: Only the admin can call this function. See {ProxyAdmin-getProxyImplementation}.\n     *\n     * TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using the\n     * https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.\n     * `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`\n     */\n    function implementation() external ifAdmin returns (address implementation_) {\n        implementation_ = _implementation();\n    }\n\n    /**\n     * @dev Changes the admin of the proxy.\n     *\n     * Emits an {AdminChanged} event.\n     *\n     * NOTE: Only the admin can call this function. See {ProxyAdmin-changeProxyAdmin}.\n     */\n    function changeAdmin(address newAdmin) external virtual ifAdmin {\n        _changeAdmin(newAdmin);\n    }\n\n    /**\n     * @dev Upgrade the implementation of the proxy.\n     *\n     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgrade}.\n     */\n    function upgradeTo(address newImplementation) external ifAdmin {\n        _upgradeToAndCall(newImplementation, bytes(\"\"), false);\n    }\n\n    /**\n     * @dev Upgrade the implementation of the proxy, and then call a function from the new implementation as specified\n     * by `data`, which should be an encoded function call. This is useful to initialize new storage variables in the\n     * proxied contract.\n     *\n     * NOTE: Only the admin can call this function. See {ProxyAdmin-upgradeAndCall}.\n     */\n    function upgradeToAndCall(address newImplementation, bytes calldata data) external payable ifAdmin {\n        _upgradeToAndCall(newImplementation, data, true);\n    }\n\n    /**\n     * @dev Returns the current admin.\n     */\n    function _admin() internal view virtual returns (address) {\n        return _getAdmin();\n    }\n\n    /**\n     * @dev Makes sure the admin cannot access the fallback function. See {Proxy-_beforeFallback}.\n     */\n    function _beforeFallback() internal virtual override {\n        require(msg.sender != _getAdmin(), \"TransparentUpgradeableProxy: admin cannot fallback to proxy target\");\n        super._beforeFallback();\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/ERC1967/ERC1967Proxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Proxy.sol\";\nimport \"./ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an\n * implementation address that can be changed. This address is stored in storage in the location specified by\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the\n * implementation behind the proxy.\n */\ncontract ERC1967Proxy is Proxy, ERC1967Upgrade {\n    /**\n     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.\n     *\n     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded\n     * function call, and allows initializating the storage of the proxy like a Solidity constructor.\n     */\n    constructor(address _logic, bytes memory _data) payable {\n        assert(_IMPLEMENTATION_SLOT == bytes32(uint256(keccak256(\"eip1967.proxy.implementation\")) - 1));\n        _upgradeToAndCall(_logic, _data, false);\n    }\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function _implementation() internal view virtual override returns (address impl) {\n        return ERC1967Upgrade._getImplementation();\n    }\n}\n"
    },
    "@openzeppelin/contracts/proxy/Proxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM\n * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to\n * be specified by overriding the virtual {_implementation} function.\n *\n * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a\n * different contract through the {_delegate} function.\n *\n * The success and return data of the delegated call will be returned back to the caller of the proxy.\n */\nabstract contract Proxy {\n    /**\n     * @dev Delegates the current call to `implementation`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _delegate(address implementation) internal virtual {\n        assembly {\n            // Copy msg.data. We take full control of memory in this inline assembly\n            // block because it will not return to Solidity code. We overwrite the\n            // Solidity scratch pad at memory position 0.\n            calldatacopy(0, 0, calldatasize())\n\n            // Call the implementation.\n            // out and outsize are 0 because we don't know the size yet.\n            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)\n\n            // Copy the returned data.\n            returndatacopy(0, 0, returndatasize())\n\n            switch result\n            // delegatecall returns 0 on error.\n            case 0 {\n                revert(0, returndatasize())\n            }\n            default {\n                return(0, returndatasize())\n            }\n        }\n    }\n\n    /**\n     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function\n     * and {_fallback} should delegate.\n     */\n    function _implementation() internal view virtual returns (address);\n\n    /**\n     * @dev Delegates the current call to the address returned by `_implementation()`.\n     *\n     * This function does not return to its internal call site, it will return directly to the external caller.\n     */\n    function _fallback() internal virtual {\n        _beforeFallback();\n        _delegate(_implementation());\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other\n     * function in the contract matches the call data.\n     */\n    fallback() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data\n     * is empty.\n     */\n    receive() external payable virtual {\n        _fallback();\n    }\n\n    /**\n     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`\n     * call, or as part of the Solidity `fallback` or `receive` functions.\n     *\n     * If overridden should call `super._beforeFallback()`.\n     */\n    function _beforeFallback() internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../beacon/IBeacon.sol\";\nimport \"../../interfaces/draft-IERC1822.sol\";\nimport \"../../utils/Address.sol\";\nimport \"../../utils/StorageSlot.sol\";\n\n/**\n * @dev This abstract contract provides getters and event emitting update functions for\n * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.\n *\n * _Available since v4.1._\n *\n * @custom:oz-upgrades-unsafe-allow delegatecall\n */\nabstract contract ERC1967Upgrade {\n    // This is the keccak-256 hash of \"eip1967.proxy.rollback\" subtracted by 1\n    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;\n\n    /**\n     * @dev Storage slot with the address of the current implementation.\n     * This is the keccak-256 hash of \"eip1967.proxy.implementation\" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n\n    /**\n     * @dev Emitted when the implementation is upgraded.\n     */\n    event Upgraded(address indexed implementation);\n\n    /**\n     * @dev Returns the current implementation address.\n     */\n    function _getImplementation() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 implementation slot.\n     */\n    function _setImplementation(address newImplementation) private {\n        require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n    }\n\n    /**\n     * @dev Perform implementation upgrade\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeTo(address newImplementation) internal {\n        _setImplementation(newImplementation);\n        emit Upgraded(newImplementation);\n    }\n\n    /**\n     * @dev Perform implementation upgrade with additional setup call.\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeToAndCall(\n        address newImplementation,\n        bytes memory data,\n        bool forceCall\n    ) internal {\n        _upgradeTo(newImplementation);\n        if (data.length > 0 || forceCall) {\n            Address.functionDelegateCall(newImplementation, data);\n        }\n    }\n\n    /**\n     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.\n     *\n     * Emits an {Upgraded} event.\n     */\n    function _upgradeToAndCallUUPS(\n        address newImplementation,\n        bytes memory data,\n        bool forceCall\n    ) internal {\n        // Upgrades from old implementations will perform a rollback test. This test requires the new\n        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing\n        // this special case will break upgrade paths from old UUPS implementation to new ones.\n        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {\n            _setImplementation(newImplementation);\n        } else {\n            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {\n                require(slot == _IMPLEMENTATION_SLOT, \"ERC1967Upgrade: unsupported proxiableUUID\");\n            } catch {\n                revert(\"ERC1967Upgrade: new implementation is not UUPS\");\n            }\n            _upgradeToAndCall(newImplementation, data, forceCall);\n        }\n    }\n\n    /**\n     * @dev Storage slot with the admin of the contract.\n     * This is the keccak-256 hash of \"eip1967.proxy.admin\" subtracted by 1, and is\n     * validated in the constructor.\n     */\n    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\n\n    /**\n     * @dev Emitted when the admin account has changed.\n     */\n    event AdminChanged(address previousAdmin, address newAdmin);\n\n    /**\n     * @dev Returns the current admin.\n     */\n    function _getAdmin() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new address in the EIP1967 admin slot.\n     */\n    function _setAdmin(address newAdmin) private {\n        require(newAdmin != address(0), \"ERC1967: new admin is the zero address\");\n        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;\n    }\n\n    /**\n     * @dev Changes the admin of the proxy.\n     *\n     * Emits an {AdminChanged} event.\n     */\n    function _changeAdmin(address newAdmin) internal {\n        emit AdminChanged(_getAdmin(), newAdmin);\n        _setAdmin(newAdmin);\n    }\n\n    /**\n     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.\n     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.\n     */\n    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;\n\n    /**\n     * @dev Emitted when the beacon is upgraded.\n     */\n    event BeaconUpgraded(address indexed beacon);\n\n    /**\n     * @dev Returns the current beacon.\n     */\n    function _getBeacon() internal view returns (address) {\n        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;\n    }\n\n    /**\n     * @dev Stores a new beacon in the EIP1967 beacon slot.\n     */\n    function _setBeacon(address newBeacon) private {\n        require(Address.isContract(newBeacon), \"ERC1967: new beacon is not a contract\");\n        require(\n            Address.isContract(IBeacon(newBeacon).implementation()),\n            \"ERC1967: beacon implementation is not a contract\"\n        );\n        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;\n    }\n\n    /**\n     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does\n     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).\n     *\n     * Emits a {BeaconUpgraded} event.\n     */\n    function _upgradeBeaconToAndCall(\n        address newBeacon,\n        bytes memory data,\n        bool forceCall\n    ) internal {\n        _setBeacon(newBeacon);\n        emit BeaconUpgraded(newBeacon);\n        if (data.length > 0 || forceCall) {\n            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/interfaces/draft-IERC1822.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified\n * proxy whose upgrades are fully controlled by the current implementation.\n */\ninterface IERC1822Proxiable {\n    /**\n     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation\n     * address.\n     *\n     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks\n     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this\n     * function revert if invoked through a proxy.\n     */\n    function proxiableUUID() external view returns (bytes32);\n}\n"
    },
    "@openzeppelin/contracts/utils/StorageSlot.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/StorageSlot.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC1967 implementation slot:\n * ```\n * contract ERC1967 {\n *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n *     function _getImplementation() internal view returns (address) {\n *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n *     }\n *\n *     function _setImplementation(address newImplementation) internal {\n *         require(Address.isContract(newImplementation), \"ERC1967: new implementation is not a contract\");\n *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n *     }\n * }\n * ```\n *\n * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._\n */\nlibrary StorageSlot {\n    struct AddressSlot {\n        address value;\n    }\n\n    struct BooleanSlot {\n        bool value;\n    }\n\n    struct Bytes32Slot {\n        bytes32 value;\n    }\n\n    struct Uint256Slot {\n        uint256 value;\n    }\n\n    /**\n     * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n     */\n    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.\n     */\n    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.\n     */\n    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n        assembly {\n            r.slot := slot\n        }\n    }\n\n    /**\n     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.\n     */\n    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n        assembly {\n            r.slot := slot\n        }\n    }\n}\n"
    },
    "contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol';\n"
    },
    "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/BeaconProxy.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IBeacon.sol\";\nimport \"../Proxy.sol\";\nimport \"../ERC1967/ERC1967Upgrade.sol\";\n\n/**\n * @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.\n *\n * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't\n * conflict with the storage layout of the implementation behind the proxy.\n *\n * _Available since v3.4._\n */\ncontract BeaconProxy is Proxy, ERC1967Upgrade {\n    /**\n     * @dev Initializes the proxy with `beacon`.\n     *\n     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This\n     * will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity\n     * constructor.\n     *\n     * Requirements:\n     *\n     * - `beacon` must be a contract with the interface {IBeacon}.\n     */\n    constructor(address beacon, bytes memory data) payable {\n        assert(_BEACON_SLOT == bytes32(uint256(keccak256(\"eip1967.proxy.beacon\")) - 1));\n        _upgradeBeaconToAndCall(beacon, data, false);\n    }\n\n    /**\n     * @dev Returns the current beacon address.\n     */\n    function _beacon() internal view virtual returns (address) {\n        return _getBeacon();\n    }\n\n    /**\n     * @dev Returns the current implementation address of the associated beacon.\n     */\n    function _implementation() internal view virtual override returns (address) {\n        return IBeacon(_getBeacon()).implementation();\n    }\n\n    /**\n     * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}.\n     *\n     * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.\n     *\n     * Requirements:\n     *\n     * - `beacon` must be a contract.\n     * - The implementation returned by `beacon` must be a contract.\n     */\n    function _setBeacon(address beacon, bytes memory data) internal virtual {\n        _upgradeBeaconToAndCall(beacon, data, false);\n    }\n}\n"
    },
    "contracts/controller/Controller.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/control/unstructured/UInitializable.sol\";\nimport \"@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol\";\nimport \"../interfaces/IController.sol\";\nimport \"../interfaces/ICollateral.sol\";\nimport \"../interfaces/IIncentivizer.sol\";\nimport \"../interfaces/IProduct.sol\";\n\n/**\n * @title Controller\n * @notice Manages creating new products and global protocol parameters.\n */\ncontract Controller is IController, UInitializable {\n    /// @dev Collateral contract address for the protocol\n    AddressStorage private constant _collateral = AddressStorage.wrap(keccak256(\"equilibria.perennial.Controller.collateral\"));\n    function collateral() public view returns (ICollateral) { return ICollateral(_collateral.read()); }\n\n    /// @dev Incentivizer contract address for the protocol\n    AddressStorage private constant _incentivizer = AddressStorage.wrap(keccak256(\"equilibria.perennial.Controller.incentivizer\"));\n    function incentivizer() public view returns (IIncentivizer) { return IIncentivizer(_incentivizer.read()); }\n\n    /// @dev Product implementation beacon address for the protocol\n    AddressStorage private constant _productBeacon = AddressStorage.wrap(keccak256(\"equilibria.perennial.Controller.productBeacon\"));\n    function productBeacon() public view returns (IBeacon) { return IBeacon(_productBeacon.read()); }\n\n    /// @dev Percent of collected fees that go to the protocol treasury vs the product treasury\n    UFixed18Storage private constant _protocolFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.Controller.protocolFee\"));\n    function protocolFee() public view returns (UFixed18) { return _protocolFee.read(); }\n\n    /// @dev Minimum allowable funding fee for a product\n    UFixed18Storage private constant _minFundingFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.Controller.minFundingFee\"));\n    function minFundingFee() public view returns (UFixed18) { return _minFundingFee.read(); }\n\n    /// @dev Fee on maintenance for liquidation\n    UFixed18Storage private constant _liquidationFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.Controller.liquidationFee\"));\n    function liquidationFee() public view returns (UFixed18) { return _liquidationFee.read(); }\n\n    /// @dev Fee on incentivization programs\n    UFixed18Storage private constant _incentivizationFee = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.Controller.incentivizationFee\"));\n    function incentivizationFee() public view returns (UFixed18) { return _incentivizationFee.read(); }\n\n    /// @dev Minimum allowable collateral amount per user account\n    UFixed18Storage private constant _minCollateral = UFixed18Storage.wrap(keccak256(\"equilibria.perennial.Controller.minCollateral\"));\n    function minCollateral() public view returns (UFixed18) { return _minCollateral.read(); }\n\n    /// @dev Maximum incentivization programs per product allowed\n    Uint256Storage private constant _programsPerProduct = Uint256Storage.wrap(keccak256(\"equilibria.perennial.Controller.programsPerProduct\"));\n    function programsPerProduct() public view returns (uint256) { return _programsPerProduct.read(); }\n\n    /// @dev Protocol pauser address. address(0) defaults to owner(0)\n    AddressStorage private constant _pauser = AddressStorage.wrap(keccak256(\"equilibria.perennial.Controller.pauser\"));\n    function pauser() public view returns (address) {\n        address pauser_ = _pauser.read();\n        return pauser_ == address(0) ? owner() : pauser_;\n    }\n\n    /// @dev The paused status of the protocol\n    BoolStorage private constant _paused = BoolStorage.wrap(keccak256(\"equilibria.perennial.Controller.paused\"));\n    function paused() public view returns (bool) { return _paused.read(); }\n\n    /// @dev List of product coordinators\n    Coordinator[] private _coordinators;\n\n    /// @dev Mapping of the coordinator for each  product\n    mapping(IProduct => uint256) public coordinatorFor;\n\n    /**\n     * @notice Initializes the contract state\n     * @dev Must be called atomically as part of the upgradeable proxy deployment to\n     *      avoid front-running\n     * @param collateral_ Collateral contract address\n     * @param incentivizer_ Incentivizer contract address\n     * @param productBeacon_ Product implementation beacon address\n     */\n    function initialize(\n        ICollateral collateral_,\n        IIncentivizer incentivizer_,\n        IBeacon productBeacon_\n    ) external initializer(1) {\n        _createCoordinator();\n\n        updateCollateral(collateral_);\n        updateIncentivizer(incentivizer_);\n        updateProductBeacon(productBeacon_);\n    }\n\n    /**\n     * @notice Creates a new coordinator with `msg.sender` as the owner\n     * @dev Can only be called by the protocol owner\n     * @return New coordinator ID\n     */\n    function createCoordinator() external returns (uint256) {\n        return _createCoordinator();\n    }\n\n    /**\n     * @notice Creates a new coordinator with `msg.sender` as the owner\n     * @dev `treasury` and `pauser` initialize as the 0-address, defaulting to the `owner`\n     * @return New coordinator ID\n     */\n    function _createCoordinator() private returns (uint256) {\n        uint256 coordinatorId = _coordinators.length;\n\n        _coordinators.push(Coordinator({\n            pendingOwner: address(0),\n            owner: msg.sender,\n            treasury: address(0)\n        }));\n\n        emit CoordinatorCreated(coordinatorId, msg.sender);\n\n        return coordinatorId;\n    }\n\n    /**\n     * @notice Updates the pending owner of an existing coordinator\n     * @dev Must be called by the coordinator's current owner\n     * @param coordinatorId Coordinator to update\n     * @param newPendingOwner New pending owner address\n     */\n    function updateCoordinatorPendingOwner(uint256 coordinatorId, address newPendingOwner) external onlyOwner(coordinatorId) {\n        _coordinators[coordinatorId].pendingOwner = newPendingOwner;\n        emit CoordinatorPendingOwnerUpdated(coordinatorId, newPendingOwner);\n    }\n\n    /**\n     * @notice Accepts ownership over an existing coordinator\n     * @dev Must be called by the coordinator's pending owner\n     * @param coordinatorId Coordinator to update\n     */\n    function acceptCoordinatorOwner(uint256 coordinatorId) external {\n        Coordinator storage coordinator = _coordinators[coordinatorId];\n        address newPendingOwner = coordinator.pendingOwner;\n\n        if (msg.sender != newPendingOwner) revert ControllerNotPendingOwnerError(coordinatorId);\n\n        coordinator.pendingOwner = address(0);\n        coordinator.owner = newPendingOwner;\n        emit CoordinatorOwnerUpdated(coordinatorId, newPendingOwner);\n    }\n\n    /**\n     * @notice Updates the treasury of an existing coordinator\n     * @dev Must be called by the coordinator's current owner. Defaults to the coordinator `owner` if set to address(0)\n     * @param coordinatorId Coordinator to update\n     * @param newTreasury New treasury address\n     */\n    function updateCoordinatorTreasury(uint256 coordinatorId, address newTreasury) external onlyOwner(coordinatorId) {\n        _coordinators[coordinatorId].treasury = newTreasury;\n        emit CoordinatorTreasuryUpdated(coordinatorId, newTreasury);\n    }\n\n    /**\n     * @notice Creates a new product market with `provider`\n     * @dev Can only be called by the coordinator owner\n     * @param coordinatorId Coordinator that will own the product\n     * @param productInfo Product params used to initialize the product\n     * @return New product contract address\n     */\n    function createProduct(uint256 coordinatorId, IProduct.ProductInfo calldata productInfo)\n    external onlyOwner(coordinatorId) returns (IProduct) {\n        if (coordinatorId == 0) revert ControllerNoZeroCoordinatorError();\n\n        BeaconProxy newProductProxy = new BeaconProxy(address(productBeacon()), abi.encodeCall(IProduct.initialize, productInfo));\n        IProduct newProduct = IProduct(address(newProductProxy));\n        coordinatorFor[newProduct] = coordinatorId;\n        emit ProductCreated(newProduct, productInfo);\n\n        return newProduct;\n    }\n\n    /**\n     * @notice Updates the Collateral contract address\n     * @param newCollateral New Collateral contract address\n     */\n    function updateCollateral(ICollateral newCollateral) public onlyOwner(0) {\n        if (!Address.isContract(address(newCollateral))) revert ControllerNotContractAddressError();\n        _collateral.store(address(newCollateral));\n        emit CollateralUpdated(newCollateral);\n    }\n\n    /**\n     * @notice Updates the Incentivizer contract address\n     * @param newIncentivizer New Incentivizer contract address\n     */\n    function updateIncentivizer(IIncentivizer newIncentivizer) public onlyOwner(0) {\n        if (!Address.isContract(address(newIncentivizer))) revert ControllerNotContractAddressError();\n        _incentivizer.store(address(newIncentivizer));\n        emit IncentivizerUpdated(newIncentivizer);\n    }\n\n    /**\n     * @notice Updates the Product implementation beacon address\n     * @param newProductBeacon New Product implementation beacon address\n     */\n    function updateProductBeacon(IBeacon newProductBeacon) public onlyOwner(0) {\n        if (!Address.isContract(address(newProductBeacon))) revert ControllerNotContractAddressError();\n        _productBeacon.store(address(newProductBeacon));\n        emit ProductBeaconUpdated(newProductBeacon);\n    }\n\n    /**\n     * @notice Updates the protocol-product fee split\n     * @param newProtocolFee New protocol-product fee split\n     */\n    function updateProtocolFee(UFixed18 newProtocolFee) public onlyOwner(0) {\n        if (newProtocolFee.gt(UFixed18Lib.ONE)) revert ControllerInvalidProtocolFeeError();\n\n        _protocolFee.store(newProtocolFee);\n        emit ProtocolFeeUpdated(newProtocolFee);\n    }\n\n    /**\n     * @notice Updates the minimum allowed funding fee\n     * @param newMinFundingFee New minimum allowed funding fee\n     */\n    function updateMinFundingFee(UFixed18 newMinFundingFee) public onlyOwner(0) {\n        if (newMinFundingFee.gt(UFixed18Lib.ONE)) revert ControllerInvalidMinFundingFeeError();\n\n        _minFundingFee.store(newMinFundingFee);\n        emit MinFundingFeeUpdated(newMinFundingFee);\n    }\n\n    /**\n     * @notice Updates the liquidation fee\n     * @param newLiquidationFee New liquidation fee\n     */\n    function updateLiquidationFee(UFixed18 newLiquidationFee) public onlyOwner(0) {\n        if (newLiquidationFee.gt(UFixed18Lib.ONE)) revert ControllerInvalidLiquidationFeeError();\n\n        _liquidationFee.store(newLiquidationFee);\n        emit LiquidationFeeUpdated(newLiquidationFee);\n    }\n\n    /**\n     * @notice Updates the incentivization fee\n     * @param newIncentivizationFee New incentivization fee\n     */\n    function updateIncentivizationFee(UFixed18 newIncentivizationFee) public onlyOwner(0) {\n        if (newIncentivizationFee.gt(UFixed18Lib.ONE)) revert ControllerInvalidIncentivizationFeeError();\n\n        _incentivizationFee.store(newIncentivizationFee);\n        emit IncentivizationFeeUpdated(newIncentivizationFee);\n    }\n\n    /**\n     * @notice Updates the minimum allowed collateral amount per user account\n     * @param newMinCollateral New minimum allowed collateral amount\n     */\n    function updateMinCollateral(UFixed18 newMinCollateral) public onlyOwner(0) {\n        _minCollateral.store(newMinCollateral);\n        emit MinCollateralUpdated(newMinCollateral);\n    }\n\n    /**\n     * @notice Updates the maximum incentivization programs per product allowed\n     * @param newProgramsPerProduct New maximum incentivization programs per product allowed\n     */\n    function updateProgramsPerProduct(uint256 newProgramsPerProduct) public onlyOwner(0) {\n        _programsPerProduct.store(newProgramsPerProduct);\n        emit ProgramsPerProductUpdated(newProgramsPerProduct);\n    }\n\n    /**\n     * @notice Updates the protocol pauser address. Zero address defaults to owner(0)\n     * @param newPauser New protocol pauser address\n     */\n    function updatePauser(address newPauser) public onlyOwner(0) {\n        _pauser.store(newPauser);\n        emit PauserUpdated(newPauser);\n    }\n\n    /**\n     * @notice Updates the protocol paused state\n     * @param newPaused New protocol paused state\n     */\n    function updatePaused(bool newPaused) public onlyPauser {\n        _paused.store(newPaused);\n        emit PausedUpdated(newPaused);\n    }\n\n    /**\n     * @notice Returns whether a contract is a product\n     * @param product Contract address to check\n     * @return Whether a contract is a product\n     */\n    function isProduct(IProduct product) external view returns (bool) {\n        return coordinatorFor[product] != 0;\n    }\n\n    /**\n     * @notice Returns coordinator state for coordinator `coordinatorId`\n     * @param coordinatorId Coordinator to return for\n     * @return Coordinator state\n     */\n    function coordinators(uint256 coordinatorId) external view returns (Coordinator memory) {\n        return _coordinators[coordinatorId];\n    }\n\n    /**\n     * @notice Returns the pending owner of the protocol\n     * @return Owner of the protocol\n     */\n    function pendingOwner() public view returns (address) {\n        return pendingOwner(0);\n    }\n\n    /**\n     * @notice Returns the pending owner of the coordinator `coordinatorId`\n     * @param coordinatorId Coordinator to return for\n     * @return Pending owner of the coordinator\n     */\n    function pendingOwner(uint256 coordinatorId) public view returns (address) {\n        return _coordinators[coordinatorId].pendingOwner;\n    }\n\n    /**\n     * @notice Returns the owner of the protocol\n     * @return Owner of the protocol\n     */\n    function owner() public view returns (address) {\n        return owner(0);\n    }\n\n    /**\n     * @notice Returns the owner of the coordinator `coordinatorId`\n     * @param coordinatorId Coordinator to return for\n     * @return Owner of the coordinator\n     */\n    function owner(uint256 coordinatorId) public view returns (address) {\n        return _coordinators[coordinatorId].owner;\n    }\n\n    /**\n     * @notice Returns the owner of the product `product`\n     * @param product Product to return for\n     * @return Owner of the product\n     */\n    function owner(IProduct product) external view returns (address) {\n        return owner(coordinatorFor[product]);\n    }\n\n    /**\n     * @notice Returns the treasury of the protocol\n     * @dev Defaults to the `owner` when `treasury` is unset\n     * @return Treasury of the protocol\n     */\n    function treasury() external view returns (address) {\n        return treasury(0);\n    }\n\n    /**\n     * @notice Returns the treasury of the coordinator `coordinatorId`\n     * @dev Defaults to the `owner` when `treasury` is unset\n     * @param coordinatorId Coordinator to return for\n     * @return Treasury of the coordinator\n     */\n    function treasury(uint256 coordinatorId) public view returns (address) {\n        address _treasury = _coordinators[coordinatorId].treasury;\n        return _treasury == address(0) ? owner(coordinatorId) : _treasury;\n    }\n\n    /**\n     * @notice Returns the treasury of the product `product`\n     * @dev Defaults to the `owner` when `treasury` is unset\n     * @param product Product to return for\n     * @return Treasury of the product\n     */\n    function treasury(IProduct product) external view returns (address) {\n        return treasury(coordinatorFor[product]);\n    }\n\n    /// @dev Only allow owner of `coordinatorId` to call\n    modifier onlyOwner(uint256 coordinatorId) {\n        if (msg.sender != owner(coordinatorId)) revert ControllerNotOwnerError(coordinatorId);\n\n        _;\n    }\n\n    /// @dev Only allow the pauser to call\n    modifier onlyPauser {\n        if (msg.sender != pauser()) revert ControllerNotPauserError();\n\n        _;\n    }\n}\n"
    },
    "contracts/incentivizer/Incentivizer.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/control/unstructured/UInitializable.sol\";\nimport \"@equilibria/root/control/unstructured/UReentrancyGuard.sol\";\nimport \"../interfaces/IIncentivizer.sol\";\nimport \"../interfaces/IController.sol\";\nimport \"../controller/UControllerProvider.sol\";\nimport \"./types/ProductManager.sol\";\n\n/**\n * @title Incentivizer\n * @notice Manages logic and state for all incentive programs in the protocol.\n */\ncontract Incentivizer is IIncentivizer, UInitializable, UControllerProvider, UReentrancyGuard {\n    /// @dev Product management state\n    mapping(IProduct => ProductManager) private _products;\n\n    /// @dev Fees that have been collected, but remain unclaimed\n    mapping(Token18 => UFixed18) public fees;\n\n    /**\n     * @notice Initializes the contract state\n     * @dev Must be called atomically as part of the upgradeable proxy deployment to\n     *      avoid front-running\n     * @param controller_ Factory contract address\n     */\n    function initialize(IController controller_) external initializer(1) {\n        __UControllerProvider__initialize(controller_);\n        __UReentrancyGuard__initialize();\n    }\n\n    /**\n     * @notice Creates a new incentive program\n     * @dev Must be called as the product or protocol owner\n     * @param product The product to create the new program on\n     * @param programInfo Parameters for the new program\n     * @return programId New program's ID\n     */\n    function create(IProduct product, ProgramInfo calldata programInfo)\n    external\n    nonReentrant\n    isProduct(product)\n    notPaused\n    onlyOwner(programInfo.coordinatorId)\n    returns (uint256 programId) {\n        IController _controller = controller();\n\n        // Validate\n        if (programInfo.coordinatorId != 0 && programInfo.coordinatorId != _controller.coordinatorFor(product))\n            revert IncentivizerNotAllowedError(product);\n        if (active(product) >= _controller.programsPerProduct())\n            revert IncentivizerTooManyProgramsError();\n        ProgramInfoLib.validate(programInfo);\n\n        // Take fee\n        (ProgramInfo memory newProgramInfo, UFixed18 programFeeAmount) = ProgramInfoLib.deductFee(programInfo, _controller.incentivizationFee());\n        fees[newProgramInfo.token] = fees[newProgramInfo.token].add(programFeeAmount);\n\n        // Register program\n        programId = _products[product].register(newProgramInfo);\n\n        // Charge creator\n        newProgramInfo.token.pull(msg.sender, programInfo.amount.sum());\n\n        emit ProgramCreated(\n            product,\n            programId,\n            newProgramInfo,\n            programFeeAmount\n        );\n    }\n\n    /**\n     * @notice Completes an in-progress program early\n     * @dev Must be called as the program owner\n     * @param product Product that the program is running on\n     * @param programId Program to complete early\n     */\n    function complete(IProduct product, uint256 programId)\n    external\n    nonReentrant\n    isProgram(product, programId)\n    notPaused\n    onlyProgramOwner(product, programId)\n    {\n        ProductManagerLib.SyncResult memory syncResult = _products[product].complete(product, programId);\n        _handleSyncResult(product, syncResult);\n    }\n\n    /**\n     * @notice Starts and completes programs as they become available\n     * @dev Called every settle() from each product\n     * @param currentOracleVersion The preloaded current oracle version\n     */\n    function sync(IOracleProvider.OracleVersion memory currentOracleVersion) external onlyProduct {\n        IProduct product = IProduct(msg.sender);\n\n        ProductManagerLib.SyncResult[] memory syncResults = _products[product].sync(product, currentOracleVersion);\n        for (uint256 i = 0; i < syncResults.length; i++) {\n            _handleSyncResult(product, syncResults[i]);\n        }\n    }\n\n    /**\n     * @notice Handles refunding and event emitting on program start and completion\n     * @param product Product that the program is running on\n     * @param syncResult The data from the sync event to handle\n     */\n    function _handleSyncResult(IProduct product, ProductManagerLib.SyncResult memory syncResult) private {\n        uint256 programId = syncResult.programId;\n        if (!syncResult.refundAmount.isZero())\n            _products[product].token(programId).push(treasury(product, programId), syncResult.refundAmount);\n        if (syncResult.versionStarted != 0)\n            emit ProgramStarted(product, programId, syncResult.versionStarted);\n        if (syncResult.versionComplete != 0)\n            emit ProgramComplete(product, programId, syncResult.versionComplete);\n    }\n\n    /**\n     * @notice Settles unsettled balance for `account`\n     * @dev Called immediately proceeding a position update in the corresponding product\n     * @param account Account to sync\n     * @param currentOracleVersion The preloaded current oracle version\n     */\n    function syncAccount(\n        address account,\n        IOracleProvider.OracleVersion memory currentOracleVersion\n    ) external onlyProduct {\n        IProduct product = IProduct(msg.sender);\n        _products[product].syncAccount(product, account, currentOracleVersion);\n    }\n\n    /**\n     * @notice Claims all of `msg.sender`'s rewards for `product` programs\n     * @param product Product to claim rewards for\n     * @param programIds Programs to claim rewards for\n     */\n    function claim(IProduct product, uint256[] calldata programIds)\n    external\n    nonReentrant\n    {\n        _claimProduct(product, programIds);\n    }\n\n    /**\n     * @notice Claims all of `msg.sender`'s rewards for a specific program\n     * @param products Products to claim rewards for\n     * @param programIds Programs to claim rewards for\n     */\n    function claim(IProduct[] calldata products, uint256[][] calldata programIds)\n    external\n    nonReentrant\n    {\n        if (products.length != programIds.length) revert IncentivizerBatchClaimArgumentMismatchError();\n        for (uint256 i; i < products.length; i++) {\n            _claimProduct(products[i], programIds[i]);\n        }\n    }\n\n    /**\n     * @notice Claims all of `msg.sender`'s rewards for `product` programs\n     * @dev Internal helper with validation checks\n     * @param product Product to claim rewards for\n     * @param programIds Programs to claim rewards for\n     */\n    function _claimProduct(IProduct product, uint256[] memory programIds)\n    private\n    isProduct(product)\n    notPaused\n    settleForAccount(msg.sender, product)\n    {\n        for (uint256 i; i < programIds.length; i++) {\n            _claimProgram(product, programIds[i]);\n        }\n    }\n\n    /**\n     * @notice Claims all of `msg.sender`'s rewards for `programId` on `product`\n     * @dev Internal helper with validation checks\n     * @param product Product to claim rewards for\n     * @param programId Program to claim rewards for\n     */\n    function _claimProgram(IProduct product, uint256 programId)\n    private\n    isProgram(product, programId)\n    {\n        ProductManager storage productManager = _products[product];\n        UFixed18 claimAmount = productManager.claim(msg.sender, programId);\n        productManager.token(programId).push(msg.sender, claimAmount);\n        emit Claim(product, msg.sender, programId, claimAmount);\n    }\n\n    /**\n     * @notice Claims all `tokens` fees to the protocol treasury\n     * @param tokens Tokens to claim fees for\n     */\n    function claimFee(Token18[] calldata tokens) external notPaused {\n        for(uint256 i; i < tokens.length; i++) {\n            Token18 token = tokens[i];\n            UFixed18 amount = fees[token];\n\n            fees[token] = UFixed18Lib.ZERO;\n            token.push(controller().treasury(), amount);\n\n            emit FeeClaim(token, amount);\n        }\n    }\n\n    /**\n     * @notice Returns the quantity of active programs for a given product\n     * @param product Product to check for\n     * @return Number of active programs\n     */\n    function active(IProduct product) public view returns (uint256) {\n        return _products[product].active();\n    }\n\n    /**\n     * @notice Returns the quantity of programs for a given product\n     * @param product Product to check for\n     * @return Number of programs (inactive or active)\n     */\n    function count(IProduct product) external view returns (uint256) {\n        return _products[product].programInfos.length;\n    }\n\n    /**\n     * @notice Returns program info for program `programId`\n     * @param product Product to return for\n     * @param programId Program to return for\n     * @return Program info\n     */\n    function programInfos(IProduct product, uint256 programId) external view returns (ProgramInfo memory) {\n        return _products[product].programInfos[programId];\n    }\n\n    /**\n     * @notice Returns `account`'s total unclaimed rewards for a specific program\n     * @param product Product to return for\n     * @param account Account to return for\n     * @param programId Program to return for\n     * @return `account`'s total unclaimed rewards for `programId`\n     */\n    function unclaimed(IProduct product, address account, uint256 programId) external view returns (UFixed18) {\n        return _products[product].unclaimed(account, programId);\n    }\n\n    /**\n     * @notice Returns available rewards for a specific program\n     * @param product Product to return for\n     * @param programId Program to return for\n     * @return Available rewards for `programId`\n     */\n    function available(IProduct product, uint256 programId) external view returns (UFixed18) {\n        return _products[product].programs[programId].available;\n    }\n\n    /**\n     * @notice Returns the version started for a specific program\n     * @param product Product to return for\n     * @param programId Program to return for\n     * @return The version started for `programId`\n     */\n    function versionStarted(IProduct product, uint256 programId) external view returns (uint256) {\n        return _products[product].programs[programId].versionStarted;\n    }\n\n    /**\n     * @notice Returns the version completed for a specific program\n     * @param product Product to return for\n     * @param programId Program to return for\n     * @return The version completed for `programId`\n     */\n    function versionComplete(IProduct product, uint256 programId) external view returns (uint256) {\n        return _products[product].programs[programId].versionComplete;\n    }\n\n    /**\n     * @notice Returns the owner of a specific program\n     * @param product Product to return for\n     * @param programId Program to return for\n     * @return The owner of `programId`\n     */\n    function owner(IProduct product, uint256 programId) public view returns (address) {\n        return controller().owner(_products[product].programInfos[programId].coordinatorId);\n    }\n\n    /**\n     * @notice Returns the treasury of a specific program\n     * @param product Product to return for\n     * @param programId Program to return for\n     * @return The treasury of `programId`\n     */\n    function treasury(IProduct product, uint256 programId) public view returns (address) {\n        return controller().treasury(_products[product].programInfos[programId].coordinatorId);\n    }\n\n    /// @dev Helper to fully settle an account's state\n    modifier settleForAccount(address account, IProduct product) {\n        product.settleAccount(account);\n\n        _;\n    }\n\n    /// @dev Only allow the owner of `programId` to call\n    modifier onlyProgramOwner(IProduct product, uint256 programId) {\n        if (msg.sender != owner(product, programId)) revert IncentivizerNotProgramOwnerError(product, programId);\n\n        _;\n    }\n\n    /// @dev Only allow a valid `programId`\n    modifier isProgram(IProduct product, uint256 programId) {\n        if (!_products[product].valid(programId)) revert IncentivizerInvalidProgramError(product, programId);\n\n        _;\n    }\n}\n"
    },
    "contracts/incentivizer/types/ProductManager.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/utils/structs/EnumerableSet.sol\";\nimport \"./Program.sol\";\n\n/// @dev ProductManager type\nstruct ProductManager {\n    /// @dev Static program state\n    ProgramInfo[] programInfos;\n\n    /// @dev Dynamic program state\n    mapping(uint256 => Program) programs;\n\n    /// @dev Mapping of all active programs for each product\n    EnumerableSet.UintSet activePrograms;\n\n    /// @dev Mapping of all active programs for each user\n    mapping(address => EnumerableSet.UintSet) activeProgramsFor;\n\n    /// @dev Mapping of the next program to watch for for each user\n    mapping(address => uint256) nextProgramFor;\n}\nusing ProductManagerLib for ProductManager global;\n\n/**\n * @title ProductManagerLib\n * @notice Library that manages each product's incentivization state and logic.\n */\nlibrary ProductManagerLib {\n    using EnumerableSet for EnumerableSet.UintSet;\n\n    /// @dev Result data for a sync event\n    struct SyncResult {\n        /// @dev The programId that was updated\n        uint256 programId;\n\n        /// @dev If non-zero, the new versionStart value of the program\n        uint256 versionStarted;\n\n        /// @dev If non-zero, the new versionComplete value of the program\n        uint256 versionComplete;\n\n        /// @dev If non-zero, the amount to refund due to completion\n        UFixed18 refundAmount;\n    }\n\n    /**\n     * @notice Registers a new program on this product\n     * @param self The Product manager to operate on\n     * @param programInfo The static program info\n     * @return programId The new program's ID\n     */\n    function register(\n        ProductManager storage self,\n        ProgramInfo memory programInfo\n    ) internal returns (uint256 programId) {\n        programId = self.programInfos.length;\n        self.programInfos.push(programInfo);\n        self.programs[programId].initialize(programInfo);\n        self.activePrograms.add(programId);\n    }\n\n    /**\n     * @notice Syncs this product with the latest data\n     * @param self The Program manager to operate on\n     * @param product This Product\n     * @param currentOracleVersion The preloaded current oracle version\n     */\n    function sync(\n        ProductManager storage self,\n        IProduct product,\n        IOracleProvider.OracleVersion memory currentOracleVersion\n    ) internal returns (SyncResult[] memory results) {\n\n        uint256[] memory activeProgramIds = self.activePrograms.values();\n        results = new SyncResult[](activeProgramIds.length);\n\n        for (uint256 i; i < activeProgramIds.length; i++) {\n            // Load program\n            uint256 programId = activeProgramIds[i];\n            ProgramInfo memory programInfo = self.programInfos[programId];\n            Program storage program = self.programs[programId];\n\n            // If timestamp-started, grab current version (first version after start)\n            uint256 versionStarted;\n            if (program.versionStarted == 0 && programInfo.isStarted(currentOracleVersion.timestamp)) {\n                versionStarted = _start(self, programId, currentOracleVersion);\n            }\n\n            // If timestamp-completed, grab previous version (last version before completion)\n            uint256 versionComplete;\n            UFixed18 refundAmount;\n            if (program.versionComplete == 0 && programInfo.isComplete(currentOracleVersion.timestamp)) {\n                (versionComplete, refundAmount) = _complete(self, product, programId);\n            }\n\n            // Save result\n            results[i] = SyncResult(programId, versionStarted, versionComplete, refundAmount);\n        }\n    }\n\n    /**\n     * @notice Syncs an account for this product with the latest data\n     * @dev Assumes that sync() has already been called as part of the transaction flow\n     * @param self The Program manager to operate on\n     * @param product This Product\n     * @param account The account to sync\n     * @param currentOracleVersion The preloaded current oracle version\n     */\n    function syncAccount(\n        ProductManager storage self,\n        IProduct product,\n        address account,\n        IOracleProvider.OracleVersion memory currentOracleVersion\n    ) internal {\n\n        // Add any unseen programs\n        uint256 fromProgramId = self.nextProgramFor[account];\n        uint256 toProgramId = self.programInfos.length;\n        for (uint256 programId = fromProgramId; programId < toProgramId; programId++) {\n            self.activeProgramsFor[account].add(programId);\n        }\n        self.nextProgramFor[account] = toProgramId;\n\n        // Settle programs\n        uint256[] memory activeProgramIds = self.activeProgramsFor[account].values();\n        for (uint256 i; i < activeProgramIds.length; i++) {\n            uint256 programId = activeProgramIds[i];\n            Program storage program = self.programs[programId];\n            program.settle(product, self.programInfos[programId], account, currentOracleVersion);\n            if (!self.activePrograms.contains(programId) && currentOracleVersion.version >= program.versionComplete) {\n                self.activeProgramsFor[account].remove(programId);\n            }\n        }\n    }\n\n    /**\n     * @notice Returns the quantity of active programs for this product\n     * @param self The Program manager to operate on\n     * @return The quantity of active programs\n     */\n    function active(ProductManager storage self) internal view returns (uint256) {\n        return self.activePrograms.length();\n    }\n\n    /**\n     * @notice Forces the specified program to complete if it hasn't already\n     * @param self The Program manager to operate on\n     * @param product The Product to operate on\n     * @param programId The Program to complete\n     * @return result The sync result data from completion\n     */\n    function complete(\n        ProductManager storage self,\n        IProduct product,\n        uint256 programId\n    ) internal returns (SyncResult memory result) {\n        Program storage program = self.programs[programId];\n\n        // If not started, start first\n        if (program.versionStarted == 0) {\n            result.versionStarted = _start(self, programId, product.currentVersion());\n        }\n\n        // If not completed already, complete\n        if (program.versionComplete == 0) {\n            (result.versionComplete, result.refundAmount) = _complete(self, product, programId);\n        }\n    }\n\n    /**\n     * @notice Starts the program\n     * @dev Rewards do not start accruing until the program has started\n     *      Internal helper, does not prevent incorrectly-timed starting\n     * @param self The Program manager to operate on\n     * @param programId The Program to start\n     * @param currentOracleVersion The effective starting oracle version\n     * @return versionStarted The version that the program started\n     */\n    function _start(\n        ProductManager storage self,\n        uint256 programId,\n        IOracleProvider.OracleVersion memory currentOracleVersion\n    ) internal returns (uint256 versionStarted) {\n        versionStarted = currentOracleVersion.version;\n        self.programs[programId].start(currentOracleVersion.version);\n    }\n\n    /**\n     * @notice Completes the program\n     * @dev Completion stops rewards from accruing\n     *      Internal helper, does not prevent incorrectly-timed completion\n     * @param self The Program manager to operate on\n     * @param product The Product to operate on\n     * @param programId The Program to complete\n     * @return versionComplete The version that the program complete\n     * @return refundAmount The refunded token amount\n     */\n    function _complete(\n        ProductManager storage self,\n        IProduct product,\n        uint256 programId\n    ) internal returns (uint256 versionComplete, UFixed18 refundAmount) {\n        (versionComplete, refundAmount) = self.programs[programId].complete(product, self.programInfos[programId]);\n        self.activePrograms.remove(programId);\n    }\n\n    /**\n     * @notice Claims all of `account`'s rewards for a specific program\n     * @param self The Program manager to operate on\n     * @param account Account to claim rewards for\n     * @param programId Program to claim rewards for\n     * @return Amount claimed\n     */\n    function claim(ProductManager storage self, address account, uint256 programId) internal returns (UFixed18) {\n        return self.programs[programId].claim(account);\n    }\n\n    /**\n     * @notice Returns the total amount of unclaimed rewards for account `account`\n     * @param self The Program manager to operate on\n     * @param account The account to check for\n     * @param programId The Program to check for\n     * @return Total amount of unclaimed rewards for account\n     */\n    function unclaimed(ProductManager storage self, address account, uint256 programId) internal view returns (UFixed18) {\n        if (!valid(self, programId)) return (UFixed18Lib.ZERO);\n        return self.programs[programId].settled[account];\n    }\n\n    /**\n     * @notice Returns the token denominatino of the program's rewards\n     * @param self The Program manager to operate on\n     * @param programId The Program to check for\n     * @return The token for the program\n     */\n    function token(ProductManager storage self, uint256 programId) internal view returns (Token18) {\n        return self.programInfos[programId].token;\n    }\n\n    /**\n     * @notice Returns whether the supplied programId is valid\n     * @param self The Program manager to operate on\n     * @param programId The Program to check for\n     * @return Whether the supplied programId is valid\n     */\n    function valid(ProductManager storage self, uint256 programId) internal view returns (bool) {\n        return programId < self.programInfos.length;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/structs/EnumerableSet.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Library for managing\n * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive\n * types.\n *\n * Sets have the following properties:\n *\n * - Elements are added, removed, and checked for existence in constant time\n * (O(1)).\n * - Elements are enumerated in O(n). No guarantees are made on the ordering.\n *\n * ```\n * contract Example {\n *     // Add the library methods\n *     using EnumerableSet for EnumerableSet.AddressSet;\n *\n *     // Declare a set state variable\n *     EnumerableSet.AddressSet private mySet;\n * }\n * ```\n *\n * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)\n * and `uint256` (`UintSet`) are supported.\n */\nlibrary EnumerableSet {\n    // To implement this library for multiple types with as little code\n    // repetition as possible, we write it in terms of a generic Set type with\n    // bytes32 values.\n    // The Set implementation uses private functions, and user-facing\n    // implementations (such as AddressSet) are just wrappers around the\n    // underlying Set.\n    // This means that we can only create new EnumerableSets for types that fit\n    // in bytes32.\n\n    struct Set {\n        // Storage of set values\n        bytes32[] _values;\n        // Position of the value in the `values` array, plus 1 because index 0\n        // means a value is not in the set.\n        mapping(bytes32 => uint256) _indexes;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function _add(Set storage set, bytes32 value) private returns (bool) {\n        if (!_contains(set, value)) {\n            set._values.push(value);\n            // The value is stored at length-1, but we add 1 to all indexes\n            // and use 0 as a sentinel value\n            set._indexes[value] = set._values.length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function _remove(Set storage set, bytes32 value) private returns (bool) {\n        // We read and store the value's index to prevent multiple reads from the same storage slot\n        uint256 valueIndex = set._indexes[value];\n\n        if (valueIndex != 0) {\n            // Equivalent to contains(set, value)\n            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in\n            // the array, and then remove the last element (sometimes called as 'swap and pop').\n            // This modifies the order of the array, as noted in {at}.\n\n            uint256 toDeleteIndex = valueIndex - 1;\n            uint256 lastIndex = set._values.length - 1;\n\n            if (lastIndex != toDeleteIndex) {\n                bytes32 lastValue = set._values[lastIndex];\n\n                // Move the last value to the index where the value to delete is\n                set._values[toDeleteIndex] = lastValue;\n                // Update the index for the moved value\n                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex\n            }\n\n            // Delete the slot where the moved value was stored\n            set._values.pop();\n\n            // Delete the index for the deleted slot\n            delete set._indexes[value];\n\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function _contains(Set storage set, bytes32 value) private view returns (bool) {\n        return set._indexes[value] != 0;\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function _length(Set storage set) private view returns (uint256) {\n        return set._values.length;\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function _at(Set storage set, uint256 index) private view returns (bytes32) {\n        return set._values[index];\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function _values(Set storage set) private view returns (bytes32[] memory) {\n        return set._values;\n    }\n\n    // Bytes32Set\n\n    struct Bytes32Set {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _add(set._inner, value);\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {\n        return _remove(set._inner, value);\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {\n        return _contains(set._inner, value);\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(Bytes32Set storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {\n        return _at(set._inner, index);\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {\n        return _values(set._inner);\n    }\n\n    // AddressSet\n\n    struct AddressSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(AddressSet storage set, address value) internal returns (bool) {\n        return _add(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(AddressSet storage set, address value) internal returns (bool) {\n        return _remove(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(AddressSet storage set, address value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(uint256(uint160(value))));\n    }\n\n    /**\n     * @dev Returns the number of values in the set. O(1).\n     */\n    function length(AddressSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(AddressSet storage set, uint256 index) internal view returns (address) {\n        return address(uint160(uint256(_at(set._inner, index))));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(AddressSet storage set) internal view returns (address[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        address[] memory result;\n\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n\n    // UintSet\n\n    struct UintSet {\n        Set _inner;\n    }\n\n    /**\n     * @dev Add a value to a set. O(1).\n     *\n     * Returns true if the value was added to the set, that is if it was not\n     * already present.\n     */\n    function add(UintSet storage set, uint256 value) internal returns (bool) {\n        return _add(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Removes a value from a set. O(1).\n     *\n     * Returns true if the value was removed from the set, that is if it was\n     * present.\n     */\n    function remove(UintSet storage set, uint256 value) internal returns (bool) {\n        return _remove(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns true if the value is in the set. O(1).\n     */\n    function contains(UintSet storage set, uint256 value) internal view returns (bool) {\n        return _contains(set._inner, bytes32(value));\n    }\n\n    /**\n     * @dev Returns the number of values on the set. O(1).\n     */\n    function length(UintSet storage set) internal view returns (uint256) {\n        return _length(set._inner);\n    }\n\n    /**\n     * @dev Returns the value stored at position `index` in the set. O(1).\n     *\n     * Note that there are no guarantees on the ordering of values inside the\n     * array, and it may change when more values are added or removed.\n     *\n     * Requirements:\n     *\n     * - `index` must be strictly less than {length}.\n     */\n    function at(UintSet storage set, uint256 index) internal view returns (uint256) {\n        return uint256(_at(set._inner, index));\n    }\n\n    /**\n     * @dev Return the entire set in an array\n     *\n     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed\n     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that\n     * this function has an unbounded cost, and using it as part of a state-changing function may render the function\n     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.\n     */\n    function values(UintSet storage set) internal view returns (uint256[] memory) {\n        bytes32[] memory store = _values(set._inner);\n        uint256[] memory result;\n\n        assembly {\n            result := store\n        }\n\n        return result;\n    }\n}\n"
    },
    "contracts/incentivizer/types/Program.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../../interfaces/types/ProgramInfo.sol\";\n\n/// @dev Program type\nstruct Program {\n    /// @dev Mapping of latest rewards settled for each account\n    mapping(address => UFixed18) settled;\n\n    /// @dev Total amount of rewards yet to be claimed\n    UFixed18 available;\n\n    /// @dev Oracle version that the program started, 0 when hasn't started\n    uint256 versionStarted;\n\n    /// @dev Oracle version that the program completed, 0 is still ongoing\n    uint256 versionComplete;\n}\nusing ProgramLib for Program global;\n\n/**\n * @title ProgramLib\n * @notice Library that manages all of the mutable state for a single incentivization program.\n */\nlibrary ProgramLib {\n    /**\n     * @notice Initializes the program state\n     * @param self The Program to operate on\n     * @param programInfo Static program information\n     */\n    function initialize(Program storage self, ProgramInfo memory programInfo) internal {\n        self.available = programInfo.amount.sum();\n    }\n\n    /**\n     * @notice Starts the program\n     * @dev Rewards do not start accruing until the program has started accruing\n     *      Does not stop double-starting\n     * @param self The Program to operate on\n     * @param oracleVersion The effective starting oracle version\n     */\n    function start(Program storage self, uint256 oracleVersion) internal {\n        self.versionStarted = oracleVersion;\n    }\n\n    /**\n     * @notice Completes the program\n     * @dev Completion stops rewards from accruing\n     *      Does not prevent double-completion\n     * @param self The Program to operate on\n     * @param product The Product to operate on\n     * @param programInfo Static program information\n     * @return versionComplete The version that the program completed on\n     * @return refundAmount The refund amount from the program\n     */\n    function complete(\n        Program storage self,\n        IProduct product,\n        ProgramInfo memory programInfo\n    ) internal returns (uint256 versionComplete, UFixed18 refundAmount) {\n        uint256 versionStarted = self.versionStarted;\n        versionComplete = Math.max(versionStarted, product.latestVersion());\n        self.versionComplete = versionComplete;\n\n        IOracleProvider.OracleVersion memory fromOracleVersion = product.atVersion(versionStarted);\n        IOracleProvider.OracleVersion memory toOracleVersion = product.atVersion(versionComplete);\n\n        uint256 inactiveDuration = programInfo.duration - (toOracleVersion.timestamp - fromOracleVersion.timestamp);\n        refundAmount = programInfo.amount.sum().muldiv(inactiveDuration, programInfo.duration);\n        self.available = self.available.sub(refundAmount);\n    }\n\n    /**\n     * @notice Settles unclaimed rewards for account `account`\n     * @param self The Program to operate on\n     * @param product The Product to operate on\n     * @param programInfo Static program information\n     * @param account The account to settle for\n     * @param currentOracleVersion The preloaded current oracle version\n     */\n    function settle(\n        Program storage self,\n        IProduct product,\n        ProgramInfo memory programInfo,\n        address account,\n        IOracleProvider.OracleVersion memory currentOracleVersion\n    ) internal {\n        UFixed18 unsettledAmount = _unsettled(self, product, programInfo, account, currentOracleVersion);\n        self.settled[account] = self.settled[account].add(unsettledAmount);\n        self.available = self.available.sub(unsettledAmount);\n    }\n\n    /**\n     * @notice Claims settled rewards for account `account`\n     * @param self The Program to operate on\n     * @param account The account to claim for\n     */\n    function claim(Program storage self, address account) internal returns (UFixed18 claimedAmount) {\n        claimedAmount = self.settled[account];\n        self.settled[account] = UFixed18Lib.ZERO;\n    }\n\n    /**\n     * @notice Returns the unsettled amount of unclaimed rewards for account `account`\n     * @dev Clears when a program is closed\n     *      Assumes that position is unchanged since last settlement, must be settled prior to user position update\n     * @param self The Program to operate on\n     * @param product The Product to operate on\n     * @param programInfo Static program information\n     * @param account The account to claim for\n     * @param currentOracleVersion Current oracle version\n     * @return amount Amount of unsettled rewards for account\n     */\n    function _unsettled(\n        Program storage self,\n        IProduct product,\n        ProgramInfo memory programInfo,\n        address account,\n        IOracleProvider.OracleVersion memory currentOracleVersion\n    ) private view returns (UFixed18 amount) {\n        // program stage overview\n        //\n        // V = latest user settle version, V' = current user settle version\n        // S = versionStarted, E = versionEnded\n        //\n        // (1) V   V' S           E        program not yet started\n        // (2)   V    S     V'    E        use versionStarted -> V' for userShareDelta\n        // (3)        S  V     V' E        use V -> V' for userShareDelta\n        // (4)        S     V     E   V'   use V -> versionComplete for userShareDelta\n        // (5)        S           E V   V' program already completed\n        // (6)   V    S           E   V'   use versionStarted -> versionComplete for userShareDelta\n        //\n        // NOTE: V == S and V' == E both default to the inner case\n\n        (uint256 _versionStarted, uint256 _versionComplete) = (\n            self.versionStarted == 0 ? currentOracleVersion.version : self.versionStarted, // start must be no earlier than current version\n            self.versionComplete == 0 ? type(uint256).max : self.versionComplete           // we don't know when completion occurs\n        );\n\n        // accruing must start between self.versionStarted and self.versionComplete\n        uint256 fromVersion = Math.min(_versionComplete, Math.max(_versionStarted, product.latestVersion(account)));\n        // accruing must complete between self.versionStarted and self.versionComplete, we know self.versionStarted must be no earlier than current version\n        uint256 toVersion = Math.min(_versionComplete, currentOracleVersion.version);\n\n        Accumulator memory globalShareDelta = product.shareAtVersion(toVersion).sub(product.shareAtVersion(fromVersion));\n        Accumulator memory computedUserShareDelta = product.position(account).mul(globalShareDelta);\n        amount = UFixed18Lib.from(programInfo.amountPerShare().mul(computedUserShareDelta).sum());\n    }\n}\n"
    },
    "@equilibria/emptyset-batcher/batcher/Batcher.sol": {
      "content": "//SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"@equilibria/root/token/types/Token6.sol\";\nimport \"@equilibria/root/control/unstructured/UOwnable.sol\";\nimport \"../interfaces/IBatcher.sol\";\n\nabstract contract Batcher is IBatcher, UOwnable {\n    using UFixed18Lib for UFixed18;\n    using Token18Lib for Token18;\n    using Token6Lib for Token6;\n\n    IEmptySetReserve public immutable RESERVE;\n    Token18 public immutable DSU;\n    Token6 public immutable USDC;\n\n    constructor(IEmptySetReserve reserve, Token18 dsu, Token6 usdc) {\n        RESERVE = reserve;\n        DSU = dsu;\n        USDC = usdc;\n\n        DSU.approve(address(RESERVE));\n        USDC.approve(address(RESERVE));\n\n        __UOwnable__initialize();\n    }\n\n    function totalBalance() public view returns (UFixed18) {\n        return DSU.balanceOf().add(USDC.balanceOf());\n    }\n\n    function wrap(UFixed18 amount, address to) external {\n        _wrap(amount, to);\n        emit Wrap(to, amount);\n    }\n\n    function _wrap(UFixed18 amount, address to) virtual internal {\n        USDC.pull(msg.sender, amount, true);\n        DSU.push(to, amount);\n    }\n\n    function unwrap(UFixed18 amount, address to) external {\n        _unwrap(amount, to);\n        emit Unwrap(to, amount);\n    }\n\n    function _unwrap(UFixed18 amount, address to) virtual internal {\n        DSU.pull(msg.sender, amount);\n        USDC.push(to, amount);\n    }\n\n    function rebalance() external {\n        (UFixed18 usdcBalance, UFixed18 dsuBalance) = (USDC.balanceOf(), DSU.balanceOf());\n\n        _rebalance(USDC.balanceOf(), DSU.balanceOf());\n\n        (UFixed18 oldBalance, UFixed18 newBalance) = (usdcBalance.add(dsuBalance), totalBalance());\n        if (!oldBalance.eq(newBalance)) revert BatcherBalanceMismatchError(oldBalance, newBalance);\n\n        emit Rebalance(usdcBalance, UFixed18Lib.ZERO);\n    }\n\n    function _rebalance(UFixed18 usdcBalance, UFixed18 dsuBalance) virtual internal;\n\n    function close() external onlyOwner {\n        UFixed18 usdcBalance = USDC.balanceOf();\n        if (!usdcBalance.isZero()) RESERVE.mint(usdcBalance);\n\n        UFixed18 dsuBalance = DSU.balanceOf();\n        UFixed18 repayAmount = UFixed18Lib.min(RESERVE.debt(address(this)), dsuBalance);\n        UFixed18 returnAmount = dsuBalance.sub(repayAmount);\n\n        RESERVE.repay(address(this), repayAmount);\n        if (!returnAmount.isZero()) DSU.push(address(RESERVE), dsuBalance.sub(repayAmount));\n\n        emit Close(dsuBalance);\n    }\n}\n\ninterface IEmptySetReserve {\n    function debt(address borrower) external view returns (UFixed18);\n    function repay(address borrower, UFixed18 amount) external;\n    function mint(UFixed18 amount) external;\n    function redeem(UFixed18 amount) external;\n}\n"
    },
    "@equilibria/root/token/types/Token6.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"../../number/types/UFixed18.sol\";\n\n/// @dev Token6\ntype Token6 is address;\nusing Token6Lib for Token6 global;\ntype Token6Storage is bytes32;\nusing Token6StorageLib for Token6Storage global;\n\n/**\n * @title Token6Lib\n * @notice Library to manage 6-decimal ERC20s that is compliant with the fixed-decimal types.\n * @dev Automatically converts from Base-6 token amounts to Base-18 UFixed18 amounts, with optional rounding\n */\nlibrary Token6Lib {\n    using SafeERC20 for IERC20;\n\n    Token6 public constant ZERO = Token6.wrap(address(0));\n\n    uint256 private constant OFFSET = 1e12;\n\n    /**\n     * @notice Returns whether a token is the zero address\n     * @param self Token to check for\n     * @return Whether the token is the zero address\n     */\n    function isZero(Token6 self) internal pure returns (bool) {\n        return Token6.unwrap(self) == Token6.unwrap(ZERO);\n    }\n\n    /**\n     * @notice Returns whether the two tokens are equal\n     * @param a First token to compare\n     * @param b Second token to compare\n     * @return Whether the two tokens are equal\n     */\n    function eq(Token6 a, Token6 b) internal pure returns (bool) {\n        return Token6.unwrap(a) ==  Token6.unwrap(b);\n    }\n\n    /**\n     * @notice Approves `grantee` to spend infinite tokens from the caller\n     * @param self Token to transfer\n     * @param grantee Address to allow spending\n     */\n    function approve(Token6 self, address grantee) internal {\n        IERC20(Token6.unwrap(self)).safeApprove(grantee, type(uint256).max);\n    }\n\n    /**\n     * @notice Approves `grantee` to spend `amount` tokens from the caller\n     * @dev There are important race conditions to be aware of when using this function\n            with values other than 0. This will revert if moving from non-zero to non-zero amounts\n            See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a55b7d13722e7ce850b626da2313f3e66ca1d101/contracts/token/ERC20/IERC20.sol#L57\n     * @param self Token to transfer\n     * @param grantee Address to allow spending\n     * @param amount Amount of tokens to approve to spend\n     */\n    function approve(Token6 self, address grantee, UFixed18 amount) internal {\n        IERC20(Token6.unwrap(self)).safeApprove(grantee, toTokenAmount(amount, false));\n    }\n\n    /**\n     * @notice Approves `grantee` to spend `amount` tokens from the caller\n     * @dev There are important race conditions to be aware of when using this function\n            with values other than 0. This will revert if moving from non-zero to non-zero amounts\n            See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/a55b7d13722e7ce850b626da2313f3e66ca1d101/contracts/token/ERC20/IERC20.sol#L57\n     * @param self Token to transfer\n     * @param grantee Address to allow spending\n     * @param amount Amount of tokens to approve to spend\n     * @param roundUp Whether to round decimal token amount up to the next unit\n     */\n    function approve(Token6 self, address grantee, UFixed18 amount, bool roundUp) internal {\n        IERC20(Token6.unwrap(self)).safeApprove(grantee, toTokenAmount(amount, roundUp));\n    }\n\n    /**\n     * @notice Transfers all held tokens from the caller to the `recipient`\n     * @param self Token to transfer\n     * @param recipient Address to receive the tokens\n     */\n    function push(Token6 self, address recipient) internal {\n        push(self, recipient, balanceOf(self, address(this)));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the caller to the `recipient`\n     * @param self Token to transfer\n     * @param recipient Address to transfer tokens to\n     * @param amount Amount of tokens to transfer\n     */\n    function push(Token6 self, address recipient, UFixed18 amount) internal {\n        IERC20(Token6.unwrap(self)).safeTransfer(recipient, toTokenAmount(amount, false));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the caller to the `recipient`\n     * @param self Token to transfer\n     * @param recipient Address to transfer tokens to\n     * @param amount Amount of tokens to transfer\n     * @param roundUp Whether to round decimal token amount up to the next unit\n     */\n    function push(Token6 self, address recipient, UFixed18 amount, bool roundUp) internal {\n        IERC20(Token6.unwrap(self)).safeTransfer(recipient, toTokenAmount(amount, roundUp));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the `benefactor` to the caller\n     * @dev Reverts if trying to pull Ether\n     * @param self Token to transfer\n     * @param benefactor Address to transfer tokens from\n     * @param amount Amount of tokens to transfer\n     */\n    function pull(Token6 self, address benefactor, UFixed18 amount) internal {\n        IERC20(Token6.unwrap(self)).safeTransferFrom(benefactor, address(this), toTokenAmount(amount, false));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the `benefactor` to the caller\n     * @dev Reverts if trying to pull Ether\n     * @param self Token to transfer\n     * @param benefactor Address to transfer tokens from\n     * @param amount Amount of tokens to transfer\n     * @param roundUp Whether to round decimal token amount up to the next unit\n     */\n    function pull(Token6 self, address benefactor, UFixed18 amount, bool roundUp) internal {\n        IERC20(Token6.unwrap(self)).safeTransferFrom(benefactor, address(this), toTokenAmount(amount, roundUp));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the `benefactor` to `recipient`\n     * @dev Reverts if trying to pull Ether\n     * @param self Token to transfer\n     * @param benefactor Address to transfer tokens from\n     * @param recipient Address to transfer tokens to\n     * @param amount Amount of tokens to transfer\n     */\n    function pullTo(Token6 self, address benefactor, address recipient, UFixed18 amount) internal {\n        IERC20(Token6.unwrap(self)).safeTransferFrom(benefactor, recipient, toTokenAmount(amount, false));\n    }\n\n    /**\n     * @notice Transfers `amount` tokens from the `benefactor` to `recipient`\n     * @dev Reverts if trying to pull Ether\n     * @param self Token to transfer\n     * @param benefactor Address to transfer tokens from\n     * @param recipient Address to transfer tokens to\n     * @param amount Amount of tokens to transfer\n     * @param roundUp Whether to round decimal token amount up to the next unit\n     */\n    function pullTo(Token6 self, address benefactor, address recipient, UFixed18 amount, bool roundUp) internal {\n        IERC20(Token6.unwrap(self)).safeTransferFrom(benefactor, recipient, toTokenAmount(amount, roundUp));\n    }\n\n    /**\n     * @notice Returns the name of the token\n     * @param self Token to check for\n     * @return Token name\n     */\n    function name(Token6 self) internal view returns (string memory) {\n        return IERC20Metadata(Token6.unwrap(self)).name();\n    }\n\n    /**\n     * @notice Returns the symbol of the token\n     * @param self Token to check for\n     * @return Token symbol\n     */\n    function symbol(Token6 self) internal view returns (string memory) {\n        return IERC20Metadata(Token6.unwrap(self)).symbol();\n    }\n\n    /**\n     * @notice Returns the `self` token balance of the caller\n     * @param self Token to check for\n     * @return Token balance of the caller\n     */\n    function balanceOf(Token6 self) internal view returns (UFixed18) {\n        return balanceOf(self, address(this));\n    }\n\n    /**\n     * @notice Returns the `self` token balance of `account`\n     * @param self Token to check for\n     * @param account Account to check\n     * @return Token balance of the account\n     */\n    function balanceOf(Token6 self, address account) internal view returns (UFixed18) {\n        return fromTokenAmount(IERC20(Token6.unwrap(self)).balanceOf(account));\n    }\n\n    /**\n     * @notice Converts the unsigned fixed-decimal amount into the token amount according to\n     *         it's defined decimals\n     * @dev Provides the ability to \"round up\" the token amount which is useful in situations where\n     *      are swapping one token for another and don't want to give away \"free\" units due to rounding\n     *      errors in the favor of the user.\n     * @param amount Amount to convert\n     * @param roundUp Whether to round decimal token amount up to the next unit\n     * @return Normalized token amount\n     */\n    function toTokenAmount(UFixed18 amount, bool roundUp) private pure returns (uint256) {\n        return roundUp ? Math.ceilDiv(UFixed18.unwrap(amount), OFFSET) : UFixed18.unwrap(amount) / OFFSET;\n    }\n\n    /**\n     * @notice Converts the token amount into the unsigned fixed-decimal amount according to\n     *         it's defined decimals\n     * @param amount Token amount to convert\n     * @return Normalized unsigned fixed-decimal amount\n     */\n    function fromTokenAmount(uint256 amount) private pure returns (UFixed18) {\n        return UFixed18.wrap(amount * OFFSET);\n    }\n}\n\nlibrary Token6StorageLib {\n    function read(Token6Storage self) internal view returns (Token6 value) {\n        assembly {\n            value := sload(self)\n        }\n    }\n\n    function store(Token6Storage self, Token6 value) internal {\n        assembly {\n            sstore(self, value)\n        }\n    }\n}\n"
    },
    "@equilibria/root/control/unstructured/UOwnable.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"./UInitializable.sol\";\nimport \"../../storage/UStorage.sol\";\n\n/**\n * @title UOwnable\n * @notice Library to manage the ownership lifecycle of upgradeable contracts.\n * @dev This contract has been extended from the Open Zeppelin library to include an\n *      unstructured storage pattern so that it can be safely mixed in with upgradeable\n *      contracts without affecting their storage patterns through inheritance.\n */\nabstract contract UOwnable is UInitializable {\n    event OwnerUpdated(address indexed newOwner);\n    event PendingOwnerUpdated(address indexed newPendingOwner);\n\n    error UOwnableNotOwnerError(address sender);\n    error UOwnableNotPendingOwnerError(address sender);\n\n    /// @dev The owner address\n    AddressStorage private constant _owner = AddressStorage.wrap(keccak256(\"equilibria.root.UOwnable.owner\"));\n    function owner() public view returns (address) { return _owner.read(); }\n\n    /// @dev The pending owner address\n    AddressStorage private constant _pendingOwner = AddressStorage.wrap(keccak256(\"equilibria.root.UOwnable.pendingOwner\"));\n    function pendingOwner() public view returns (address) { return _pendingOwner.read(); }\n\n    /**\n     * @notice Initializes the contract setting `msg.sender` as the initial owner\n     */\n    function __UOwnable__initialize() internal onlyInitializer {\n        _updateOwner(msg.sender);\n    }\n\n    /**\n     * @notice Updates the new pending owner\n     * @dev Can only be called by the current owner\n     *      New owner does not take affect until that address calls `acceptOwner()`\n     * @param newPendingOwner New pending owner address\n     */\n    function updatePendingOwner(address newPendingOwner) public onlyOwner {\n        _pendingOwner.store(newPendingOwner);\n        emit PendingOwnerUpdated(newPendingOwner);\n    }\n\n    /**\n     * @notice Accepts and transfers the ownership of the contract to the pending owner\n     * @dev Can only be called by the pending owner to ensure correctness\n     */\n    function acceptOwner() external {\n        if (msg.sender != pendingOwner()) revert UOwnableNotPendingOwnerError(msg.sender);\n\n        _updateOwner(pendingOwner());\n        updatePendingOwner(address(0));\n    }\n\n    /**\n     * @notice Updates the owner address\n     * @param newOwner New owner address\n     */\n    function _updateOwner(address newOwner) private {\n        _owner.store(newOwner);\n        emit OwnerUpdated(newOwner);\n    }\n\n    /// @dev Throws if called by any account other than the owner\n    modifier onlyOwner() {\n        if (owner() != msg.sender) revert UOwnableNotOwnerError(msg.sender);\n        _;\n    }\n}\n"
    },
    "@equilibria/emptyset-batcher/interfaces/IBatcher.sol": {
      "content": "//SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\n\ninterface IBatcher {\n    event Wrap(address indexed to, UFixed18 amount);\n    event Unwrap(address indexed to, UFixed18 amount);\n    event Rebalance(UFixed18 newMinted, UFixed18 newRedeemed);\n    event Close(UFixed18 amount);\n\n    error BatcherNotImplementedError();\n    error BatcherBalanceMismatchError(UFixed18 oldBalance, UFixed18 newBalance);\n\n    function totalBalance() external view returns (UFixed18);\n    function wrap(UFixed18 amount, address to) external;\n    function unwrap(UFixed18 amount, address to) external;\n    function rebalance() external;\n}\n"
    },
    "contracts/test/TestnetReserve.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\nimport \"@equilibria/emptyset-batcher/interfaces/IBatcher.sol\";\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"@equilibria/root/token/types/Token6.sol\";\n\ncontract TestnetReserve {\n    event Mint(address indexed to, UFixed18 amount);\n    event Redeem(address indexed to, UFixed18 amount);\n\n    Token18 public immutable DSU; // solhint-disable-line var-name-mixedcase\n    Token6 public immutable USDC; // solhint-disable-line var-name-mixedcase\n\n    constructor(Token18 dsu_, Token6 usdc_) {\n        DSU = dsu_;\n        USDC = usdc_;\n    }\n\n    function mint(UFixed18 amount, address to) external {\n        USDC.pull(msg.sender, amount, true);\n        ERC20PresetMinterPauser(Token18.unwrap(DSU)).mint(to, UFixed18.unwrap(amount));\n\n        emit Mint(to, amount);\n    }\n\n    function redeem(UFixed18 amount, address to) external {\n        DSU.pull(msg.sender, amount);\n        ERC20Burnable(Token18.unwrap(DSU)).burn(UFixed18.unwrap(amount));\n        USDC.push(to, amount, true);\n\n        emit Redeem(to, amount);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/presets/ERC20PresetMinterPauser.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../extensions/ERC20Burnable.sol\";\nimport \"../extensions/ERC20Pausable.sol\";\nimport \"../../../access/AccessControlEnumerable.sol\";\nimport \"../../../utils/Context.sol\";\n\n/**\n * @dev {ERC20} token, including:\n *\n *  - ability for holders to burn (destroy) their tokens\n *  - a minter role that allows for token minting (creation)\n *  - a pauser role that allows to stop all token transfers\n *\n * This contract uses {AccessControl} to lock permissioned functions using the\n * different roles - head to its documentation for details.\n *\n * The account that deploys the contract will be granted the minter and pauser\n * roles, as well as the default admin role, which will let it grant both minter\n * and pauser roles to other accounts.\n *\n * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._\n */\ncontract ERC20PresetMinterPauser is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable {\n    bytes32 public constant MINTER_ROLE = keccak256(\"MINTER_ROLE\");\n    bytes32 public constant PAUSER_ROLE = keccak256(\"PAUSER_ROLE\");\n\n    /**\n     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the\n     * account that deploys the contract.\n     *\n     * See {ERC20-constructor}.\n     */\n    constructor(string memory name, string memory symbol) ERC20(name, symbol) {\n        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());\n\n        _setupRole(MINTER_ROLE, _msgSender());\n        _setupRole(PAUSER_ROLE, _msgSender());\n    }\n\n    /**\n     * @dev Creates `amount` new tokens for `to`.\n     *\n     * See {ERC20-_mint}.\n     *\n     * Requirements:\n     *\n     * - the caller must have the `MINTER_ROLE`.\n     */\n    function mint(address to, uint256 amount) public virtual {\n        require(hasRole(MINTER_ROLE, _msgSender()), \"ERC20PresetMinterPauser: must have minter role to mint\");\n        _mint(to, amount);\n    }\n\n    /**\n     * @dev Pauses all token transfers.\n     *\n     * See {ERC20Pausable} and {Pausable-_pause}.\n     *\n     * Requirements:\n     *\n     * - the caller must have the `PAUSER_ROLE`.\n     */\n    function pause() public virtual {\n        require(hasRole(PAUSER_ROLE, _msgSender()), \"ERC20PresetMinterPauser: must have pauser role to pause\");\n        _pause();\n    }\n\n    /**\n     * @dev Unpauses all token transfers.\n     *\n     * See {ERC20Pausable} and {Pausable-_unpause}.\n     *\n     * Requirements:\n     *\n     * - the caller must have the `PAUSER_ROLE`.\n     */\n    function unpause() public virtual {\n        require(hasRole(PAUSER_ROLE, _msgSender()), \"ERC20PresetMinterPauser: must have pauser role to unpause\");\n        _unpause();\n    }\n\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override(ERC20, ERC20Pausable) {\n        super._beforeTokenTransfer(from, to, amount);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../../../utils/Context.sol\";\n\n/**\n * @dev Extension of {ERC20} that allows token holders to destroy both their own\n * tokens and those that they have an allowance for, in a way that can be\n * recognized off-chain (via event analysis).\n */\nabstract contract ERC20Burnable is Context, ERC20 {\n    /**\n     * @dev Destroys `amount` tokens from the caller.\n     *\n     * See {ERC20-_burn}.\n     */\n    function burn(uint256 amount) public virtual {\n        _burn(_msgSender(), amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, deducting from the caller's\n     * allowance.\n     *\n     * See {ERC20-_burn} and {ERC20-allowance}.\n     *\n     * Requirements:\n     *\n     * - the caller must have allowance for ``accounts``'s tokens of at least\n     * `amount`.\n     */\n    function burnFrom(address account, uint256 amount) public virtual {\n        _spendAllowance(account, _msgSender(), amount);\n        _burn(account, amount);\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/ERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./extensions/IERC20Metadata.sol\";\nimport \"../../utils/Context.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is Context, IERC20, IERC20Metadata {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `sender` to `recipient`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n        }\n        _balances[to] += amount;\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        _balances[account] += amount;\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n        }\n        _totalSupply -= amount;\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC20.sol\";\nimport \"../../../security/Pausable.sol\";\n\n/**\n * @dev ERC20 token with pausable token transfers, minting and burning.\n *\n * Useful for scenarios such as preventing trades until the end of an evaluation\n * period, or having an emergency switch for freezing all token transfers in the\n * event of a large bug.\n */\nabstract contract ERC20Pausable is ERC20, Pausable {\n    /**\n     * @dev See {ERC20-_beforeTokenTransfer}.\n     *\n     * Requirements:\n     *\n     * - the contract must not be paused.\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override {\n        super._beforeTokenTransfer(from, to, amount);\n\n        require(!paused(), \"ERC20Pausable: token transfer while paused\");\n    }\n}\n"
    },
    "@openzeppelin/contracts/access/AccessControlEnumerable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControlEnumerable.sol\";\nimport \"./AccessControl.sol\";\nimport \"../utils/structs/EnumerableSet.sol\";\n\n/**\n * @dev Extension of {AccessControl} that allows enumerating the members of each role.\n */\nabstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {\n    using EnumerableSet for EnumerableSet.AddressSet;\n\n    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {\n        return _roleMembers[role].at(index);\n    }\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {\n        return _roleMembers[role].length();\n    }\n\n    /**\n     * @dev Overload {_grantRole} to track enumerable memberships\n     */\n    function _grantRole(bytes32 role, address account) internal virtual override {\n        super._grantRole(role, account);\n        _roleMembers[role].add(account);\n    }\n\n    /**\n     * @dev Overload {_revokeRole} to track enumerable memberships\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual override {\n        super._revokeRole(role, account);\n        _roleMembers[role].remove(account);\n    }\n}\n"
    },
    "@openzeppelin/contracts/security/Pausable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    bool private _paused;\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    constructor() {\n        _paused = false;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        return _paused;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        require(!paused(), \"Pausable: paused\");\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        require(paused(), \"Pausable: not paused\");\n        _;\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n}\n"
    },
    "@openzeppelin/contracts/access/IAccessControlEnumerable.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\n\n/**\n * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.\n */\ninterface IAccessControlEnumerable is IAccessControl {\n    /**\n     * @dev Returns one of the accounts that have `role`. `index` must be a\n     * value between 0 and {getRoleMemberCount}, non-inclusive.\n     *\n     * Role bearers are not sorted in any particular way, and their ordering may\n     * change at any point.\n     *\n     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure\n     * you perform all queries on the same block. See the following\n     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]\n     * for more information.\n     */\n    function getRoleMember(bytes32 role, uint256 index) external view returns (address);\n\n    /**\n     * @dev Returns the number of accounts that have `role`. Can be used\n     * together with {getRoleMember} to enumerate all bearers of a role.\n     */\n    function getRoleMemberCount(bytes32 role) external view returns (uint256);\n}\n"
    },
    "@openzeppelin/contracts/access/AccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n *     require(hasRole(MY_ROLE, msg.sender));\n *     ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n    struct RoleData {\n        mapping(address => bool) members;\n        bytes32 adminRole;\n    }\n\n    mapping(bytes32 => RoleData) private _roles;\n\n    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n    /**\n     * @dev Modifier that checks that an account has a specific role. Reverts\n     * with a standardized message including the required role.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     *\n     * _Available since v4.1._\n     */\n    modifier onlyRole(bytes32 role) {\n        _checkRole(role);\n        _;\n    }\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n        return _roles[role].members[account];\n    }\n\n    /**\n     * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n     * Overriding this function changes the behavior of the {onlyRole} modifier.\n     *\n     * Format of the revert message is described in {_checkRole}.\n     *\n     * _Available since v4.6._\n     */\n    function _checkRole(bytes32 role) internal view virtual {\n        _checkRole(role, _msgSender());\n    }\n\n    /**\n     * @dev Revert with a standard message if `account` is missing `role`.\n     *\n     * The format of the revert reason is given by the following regular expression:\n     *\n     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n     */\n    function _checkRole(bytes32 role, address account) internal view virtual {\n        if (!hasRole(role, account)) {\n            revert(\n                string(\n                    abi.encodePacked(\n                        \"AccessControl: account \",\n                        Strings.toHexString(uint160(account), 20),\n                        \" is missing role \",\n                        Strings.toHexString(uint256(role), 32)\n                    )\n                )\n            );\n        }\n    }\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n        return _roles[role].adminRole;\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been revoked `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) public virtual override {\n        require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n        _revokeRole(role, account);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event. Note that unlike {grantRole}, this function doesn't perform any\n     * checks on the calling account.\n     *\n     * [WARNING]\n     * ====\n     * This function should only be called from the constructor when setting\n     * up the initial roles for the system.\n     *\n     * Using this function in any other way is effectively circumventing the admin\n     * system imposed by {AccessControl}.\n     * ====\n     *\n     * NOTE: This function is deprecated in favor of {_grantRole}.\n     */\n    function _setupRole(bytes32 role, address account) internal virtual {\n        _grantRole(role, account);\n    }\n\n    /**\n     * @dev Sets `adminRole` as ``role``'s admin role.\n     *\n     * Emits a {RoleAdminChanged} event.\n     */\n    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n        bytes32 previousAdminRole = getRoleAdmin(role);\n        _roles[role].adminRole = adminRole;\n        emit RoleAdminChanged(role, previousAdminRole, adminRole);\n    }\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * Internal function without access restriction.\n     */\n    function _grantRole(bytes32 role, address account) internal virtual {\n        if (!hasRole(role, account)) {\n            _roles[role].members[account] = true;\n            emit RoleGranted(role, account, _msgSender());\n        }\n    }\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * Internal function without access restriction.\n     */\n    function _revokeRole(bytes32 role, address account) internal virtual {\n        if (hasRole(role, account)) {\n            _roles[role].members[account] = false;\n            emit RoleRevoked(role, account, _msgSender());\n        }\n    }\n}\n"
    },
    "@openzeppelin/contracts/access/IAccessControl.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n    /**\n     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n     *\n     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n     * {RoleAdminChanged} not being emitted signaling this.\n     *\n     * _Available since v3.1._\n     */\n    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n    /**\n     * @dev Emitted when `account` is granted `role`.\n     *\n     * `sender` is the account that originated the contract call, an admin role\n     * bearer except when using {AccessControl-_setupRole}.\n     */\n    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Emitted when `account` is revoked `role`.\n     *\n     * `sender` is the account that originated the contract call:\n     *   - if using `revokeRole`, it is the admin role bearer\n     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)\n     */\n    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n    /**\n     * @dev Returns `true` if `account` has been granted `role`.\n     */\n    function hasRole(bytes32 role, address account) external view returns (bool);\n\n    /**\n     * @dev Returns the admin role that controls `role`. See {grantRole} and\n     * {revokeRole}.\n     *\n     * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n     */\n    function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n    /**\n     * @dev Grants `role` to `account`.\n     *\n     * If `account` had not been already granted `role`, emits a {RoleGranted}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function grantRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from `account`.\n     *\n     * If `account` had been granted `role`, emits a {RoleRevoked} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have ``role``'s admin role.\n     */\n    function revokeRole(bytes32 role, address account) external;\n\n    /**\n     * @dev Revokes `role` from the calling account.\n     *\n     * Roles are often managed via {grantRole} and {revokeRole}: this function's\n     * purpose is to provide a mechanism for accounts to lose their privileges\n     * if they are compromised (such as when a trusted device is misplaced).\n     *\n     * If the calling account had been granted `role`, emits a {RoleRevoked}\n     * event.\n     *\n     * Requirements:\n     *\n     * - the caller must be `account`.\n     */\n    function renounceRole(bytes32 role, address account) external;\n}\n"
    },
    "@openzeppelin/contracts/utils/Strings.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        // Inspired by OraclizeAPI's implementation - MIT licence\n        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n        if (value == 0) {\n            return \"0\";\n        }\n        uint256 temp = value;\n        uint256 digits;\n        while (temp != 0) {\n            digits++;\n            temp /= 10;\n        }\n        bytes memory buffer = new bytes(digits);\n        while (value != 0) {\n            digits -= 1;\n            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n            value /= 10;\n        }\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        if (value == 0) {\n            return \"0x00\";\n        }\n        uint256 temp = value;\n        uint256 length = 0;\n        while (temp != 0) {\n            length++;\n            temp >>= 8;\n        }\n        return toHexString(value, length);\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _HEX_SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
    },
    "contracts/test/TestnetBatcher.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol\";\nimport \"@equilibria/emptyset-batcher/interfaces/IBatcher.sol\";\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"@equilibria/root/token/types/Token6.sol\";\nimport \"./TestnetReserve.sol\";\n\ncontract TestnetBatcher is IBatcher {\n    TestnetReserve public reserve;\n\n    constructor(TestnetReserve reserve_) {\n        reserve = reserve_;\n\n        reserve.USDC().approve(address(reserve));\n        reserve.DSU().approve(address(reserve));\n    }\n\n    function totalBalance() external pure returns (UFixed18) {\n        return UFixed18Lib.MAX;\n    }\n\n    // Passthrough to Reserve\n    function wrap(UFixed18 amount, address to) external {\n        reserve.USDC().pull(msg.sender, amount, true);\n        reserve.mint(amount, to);\n\n        emit Wrap(to, amount);\n    }\n\n    function unwrap(UFixed18, address) external pure {\n        revert BatcherNotImplementedError();\n    }\n\n    // No-op\n    function rebalance() external pure {\n        return;\n    }\n}\n"
    },
    "contracts/interfaces/IForwarder.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"@equilibria/root/token/types/Token6.sol\";\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/emptyset-batcher/interfaces/IBatcher.sol\";\nimport \"./ICollateral.sol\";\n\ninterface IForwarder {\n    error ForwarderNotContractAddressError();\n\n    event WrapAndDeposit(address indexed account, IProduct indexed product, UFixed18 amount);\n\n    function USDC() external view returns (Token6); // solhint-disable-line func-name-mixedcase\n    function DSU() external view returns (Token18); // solhint-disable-line func-name-mixedcase\n    function batcher() external view returns (IBatcher);\n    function collateral() external view returns (ICollateral);\n    function wrapAndDeposit(address account, IProduct product, UFixed18 amount) external;\n}\n"
    },
    "contracts/interfaces/IPerennialLens.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./IProduct.sol\";\nimport \"./ICollateral.sol\";\nimport \"./IController.sol\";\n\n/**\n * @title Lens contract to conveniently pull protocol, product, and userproduct data\n * @notice All functions should be called using `callStatic`\n */\ninterface IPerennialLens {\n    /// @dev Snapshot of Protocol information\n    struct ProtocolSnapshot {\n        ICollateral collateral;\n        IIncentivizer incentivizer;\n        Token18 collateralToken;\n        UFixed18 protocolFee;\n        UFixed18 liquidationFee;\n        UFixed18 minCollateral;\n        bool paused;\n    }\n\n    /// @dev Snapshot of Product information\n    struct ProductSnapshot {\n        IProduct.ProductInfo productInfo;\n        address productAddress;\n        Fixed18 rate;\n        Fixed18 dailyRate;\n        IOracleProvider.OracleVersion latestVersion;\n        UFixed18 maintenance;\n        UFixed18 collateral;\n        UFixed18 shortfall;\n        PrePosition pre;\n        Position position;\n        UFixed18 productFee;\n        UFixed18 protocolFee;\n        Position openInterest;\n    }\n\n    /// @dev Snapshot of User state for a Product\n    struct UserProductSnapshot {\n        address productAddress;\n        address userAddress;\n        UFixed18 collateral;\n        UFixed18 maintenance;\n        PrePosition pre;\n        Position position;\n        bool liquidatable;\n        bool liquidating;\n        Position openInterest;\n        UFixed18 fees;\n        UFixed18 exposure;\n    }\n\n    // Protocol Values\n    function controller() external view returns (IController);\n    function collateral() external view returns (ICollateral);\n\n    // Snapshot Functions for batch values\n    function snapshot() external returns (ProtocolSnapshot memory);\n    function snapshots(IProduct[] calldata productAddresses) external returns (ProductSnapshot[] memory);\n    function snapshot(IProduct product) external returns (ProductSnapshot memory);\n    function snapshots(address account, IProduct[] calldata productAddresses) external returns (UserProductSnapshot[] memory);\n    function snapshot(address account, IProduct product) external returns (UserProductSnapshot memory);\n\n    // Product Values\n    function name(IProduct product) external view returns (string memory);\n    function symbol(IProduct product) external view returns (string memory);\n    function info(IProduct product) external view returns (IProduct.ProductInfo memory _info);\n    function collateral(IProduct product) external returns (UFixed18);\n    function shortfall(IProduct product) external returns (UFixed18);\n    function pre(IProduct product) external returns (PrePosition memory);\n    function fees(IProduct product) external returns (UFixed18 protocolFees, UFixed18 productFees);\n    function position(IProduct product) external returns (Position memory);\n    function globalPosition(IProduct product) external returns (PrePosition memory, Position memory);\n    function latestVersion(IProduct product) external returns (IOracleProvider.OracleVersion memory);\n    function atVersions(IProduct product, uint[] memory versions) external returns (IOracleProvider.OracleVersion[] memory prices);\n    function rate(IProduct product) external returns (Fixed18);\n    function openInterest(IProduct product) external returns (Position memory);\n    function dailyRate(IProduct product) external returns (Fixed18);\n\n    // UserProduct Values\n    function collateral(address account, IProduct product) external returns (UFixed18);\n    function maintenance(address account, IProduct product) external returns (UFixed18);\n    function liquidatable(address account, IProduct product) external returns (bool);\n    function liquidating(address account, IProduct product) external returns (bool);\n    function pre(address account, IProduct product) external returns (PrePosition memory);\n    function position(address account, IProduct product) external returns (Position memory);\n    function userPosition(address account, IProduct product) external returns (PrePosition memory, Position memory);\n    function fees(address account, IProduct product) external returns (UFixed18);\n    function openInterest(address account, IProduct product) external returns (Position memory);\n    function exposure(address account, IProduct product) external returns (UFixed18);\n    function maintenanceRequired(\n        address account,\n        IProduct product,\n        UFixed18 positionSize\n    ) external returns (UFixed18);\n    function unclaimedIncentiveRewards(address account, IProduct product)\n        external\n        returns (Token18[] memory tokens, UFixed18[] memory amounts);\n    function unclaimedIncentiveRewards(\n        address account,\n        IProduct product,\n        uint256[] calldata programIds\n    ) external returns (Token18[] memory tokens, UFixed18[] memory amounts);\n}\n"
    },
    "contracts/lens/PerennialLens.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../interfaces/IPerennialLens.sol\";\n\n/**\n * @title Lens contract to conveniently pull protocol data\n * @notice All functions should be called using `callStatic`\n */\ncontract PerennialLens is IPerennialLens {\n    /**\n     * @notice Protocol controller\n     * @return Protocol controller\n     */\n    IController public immutable controller;\n\n    /// @param _controller Protocol controller address\n    constructor(IController _controller) {\n        controller = _controller;\n    }\n\n    /**\n     * @notice Protocol collateral address\n     * @return Protocol collateral address\n     */\n    function collateral() public view returns (ICollateral) {\n        return controller.collateral();\n    }\n\n    /**\n     *  Snapshot Functions\n     */\n\n    /**\n     * @notice Returns the snapshot of the protocol\n     * @return _snapshot a snapshot of protocol values\n     */\n    function snapshot() public view returns (ProtocolSnapshot memory _snapshot) {\n        _snapshot.collateral = collateral();\n        _snapshot.incentivizer = controller.incentivizer();\n        _snapshot.collateralToken = collateral().token();\n        _snapshot.protocolFee = controller.protocolFee();\n        _snapshot.liquidationFee = controller.liquidationFee();\n        _snapshot.minCollateral = controller.minCollateral();\n        _snapshot.paused = controller.paused();\n    }\n\n    /**\n     * @notice Returns the snapshots of the provided `productAddresses`\n     * @param productAddresses Product addresses\n     * @return _snapshots a snapshot for each product after settle\n     */\n    function snapshots(IProduct[] calldata productAddresses) public returns (ProductSnapshot[] memory _snapshots) {\n        _snapshots = new ProductSnapshot[](productAddresses.length);\n        for (uint256 i = 0; i < productAddresses.length; i++) {\n            _snapshots[i] = snapshot(productAddresses[i]);\n        }\n    }\n\n    /**\n     * @notice Returns the snapshot of the provided `product`\n     * @param product Product address\n     * @return _snapshot for the product after settle\n     */\n    function snapshot(IProduct product) public settle(product) returns (ProductSnapshot memory _snapshot) {\n        _snapshot.productInfo = info(product);\n        _snapshot.productAddress = address(product);\n        _snapshot.rate = rate(product);\n        _snapshot.dailyRate = dailyRate(product);\n        _snapshot.latestVersion = latestVersion(product);\n        _snapshot.maintenance = product.maintenance();\n        _snapshot.collateral = collateral(product);\n        _snapshot.shortfall = shortfall(product);\n        _snapshot.pre = pre(product);\n        _snapshot.position = position(product);\n        (_snapshot.productFee, _snapshot.protocolFee) = fees(product);\n        _snapshot.openInterest = openInterest(product);\n    }\n\n    /**\n     * @notice Returns the user snapshots for the provided `productAddresses`\n     * @param account User addresses\n     * @param productAddresses Product addresses\n     * @return _snapshots UserSnapshot for each product after settle\n     */\n    function snapshots(address account, IProduct[] memory productAddresses)\n        public returns (UserProductSnapshot[] memory _snapshots)\n    {\n        _snapshots = new UserProductSnapshot[](productAddresses.length);\n        for (uint256 i = 0; i < productAddresses.length; i++) {\n            _snapshots[i] = snapshot(account, productAddresses[i]);\n        }\n    }\n\n    /**\n     * @notice Returns the user snapshot for the provided `product`\n     * @param account User addresses\n     * @param product Product address\n     * @return _snapshot UserSnapshot for the product after settle\n     */\n    function snapshot(address account, IProduct product)\n        public\n        settleAccount(account, product)\n        returns (UserProductSnapshot memory _snapshot)\n    {\n        _snapshot.productAddress = address(product);\n        _snapshot.userAddress = account;\n        _snapshot.collateral = collateral(account, product);\n        _snapshot.maintenance = maintenance(account, product);\n        _snapshot.pre = pre(account, product);\n        _snapshot.position = position(account, product);\n        _snapshot.liquidatable = liquidatable(account, product);\n        _snapshot.liquidating = liquidating(account, product);\n        _snapshot.openInterest = openInterest(account, product);\n        _snapshot.fees = fees(account, product);\n        _snapshot.exposure = exposure(account, product);\n    }\n\n    /**\n     *  End Snapshot Functions\n     */\n\n    /**\n     *  Product Individual Fields Functions\n     */\n\n    /**\n     * @notice Returns the name of the provided `product`\n     * @param product Product address\n     * @return Name of the product\n     */\n    function name(IProduct product) public view returns (string memory) {\n        return product.name();\n    }\n\n    /**\n     * @notice Returns the symbol of the provided `product`\n     * @param product Product address\n     * @return Symbol of the product\n     */\n    function symbol(IProduct product) public view returns (string memory) {\n        return product.symbol();\n    }\n\n    /**\n     * @notice Returns the info of the provided `product`\n     * @param product Product address\n     * @return _info of the product\n     */\n    function info(IProduct product) public view returns (IProduct.ProductInfo memory _info) {\n        _info.name = name(product);\n        _info.symbol = symbol(product);\n        _info.payoffDefinition = product.payoffDefinition();\n        _info.oracle = product.oracle();\n        _info.maintenance = product.maintenance();\n        _info.fundingFee = product.fundingFee();\n        _info.makerFee = product.makerFee();\n        _info.takerFee = product.takerFee();\n        _info.makerLimit = product.makerLimit();\n        _info.utilizationCurve = product.utilizationCurve();\n    }\n\n    /**\n     * @notice Product total collateral amount after settle\n     * @param product Product address\n     * @return Total collateral for product\n     */\n    function collateral(IProduct product) public settle(product) returns (UFixed18) {\n        return collateral().collateral(product);\n    }\n\n    /**\n     * @notice Product total shortfall amount after settle\n     * @param product Product address\n     * @return Total shortfall for product\n     */\n    function shortfall(IProduct product) public settle(product) returns (UFixed18) {\n        return collateral().shortfall(product);\n    }\n\n    /**\n     * @notice Product pre position after settle\n     * @param product Product address\n     * @return Product pre-position\n     */\n    function pre(IProduct product) public settle(product) returns (PrePosition memory) {\n        return product.pre();\n    }\n\n    /**\n     * @notice Product position after settle\n     * @param product Product address\n     * @return product position\n     */\n    function position(IProduct product) public settle(product) returns (Position memory) {\n        return _latestPosition(product);\n    }\n\n    /**\n     * @notice Product pre-position and position after settle\n     * @param product Product address\n     * @return Product pre-position\n     * @return Product position\n     */\n    function globalPosition(IProduct product) public settle(product) returns (PrePosition memory, Position memory) {\n        return (product.pre(), _latestPosition(product));\n    }\n\n    /**\n     * @notice Current price of product after settle\n     * @param product Product address\n     * @return Product latest price\n     */\n    function latestVersion(IProduct product) public settle(product) returns (IOracleProvider.OracleVersion memory) {\n        return _latestVersion(product);\n    }\n\n    /**\n     * @notice Prices of product at specified versions after settle\n     * @param product Product address\n     * @param versions Oracle versions to query\n     * @return prices Product prices at specified versions\n     */\n    function atVersions(IProduct product, uint256[] memory versions)\n        public\n        settle(product)\n        returns (IOracleProvider.OracleVersion[] memory prices)\n    {\n        prices = new IOracleProvider.OracleVersion[](versions.length);\n        for (uint256 i = 0; i < versions.length; i++) {\n            prices[i] = product.atVersion(versions[i]);\n        }\n    }\n\n    /**\n     * @notice Product funding rate after settle\n     * @param product Product address\n     * @return Product current funding rate\n     */\n    function rate(IProduct product) public settle(product) returns (Fixed18) {\n        Position memory position_ = _latestPosition(product);\n        return product.rate(position_);\n    }\n\n    /**\n     * @notice Product funding extrapolated to a daily rate after settle\n     * @param product Product address\n     * @return Product current funding extrapolated to a daily rate\n     */\n    function dailyRate(IProduct product) public settle(product) returns (Fixed18) {\n        Position memory position_ = _latestPosition(product);\n        return product.rate(position_).mul(Fixed18Lib.from(60 * 60 * 24));\n    }\n\n    /**\n     * @notice Fees accumulated by product and protocol treasuries after settle\n     * @param product Product address\n     * @return protocolFees fees accrued by the protocol\n     * @return productFees fees accrued by the product owner\n     */\n    function fees(IProduct product) public settle(product) returns (UFixed18 protocolFees, UFixed18 productFees) {\n        address protocolTreasury = controller.treasury();\n        address productTreasury = controller.treasury(product);\n\n        protocolFees = collateral().fees(protocolTreasury);\n        productFees = collateral().fees(productTreasury);\n    }\n\n    /**\n     * @notice Product total open interest after settle\n     * @param product Product address\n     * @return Product maker and taker position multiplied by latest price after settle\n     */\n    function openInterest(IProduct product) public settle(product) returns (Position memory) {\n        return _latestPosition(product).mul(_latestVersion(product).price.abs());\n    }\n\n    /**\n     *  End Product Individual Fields Functions\n     */\n\n    /**\n     *  UserProduct Individual Fields Functions\n     */\n\n    /**\n     * @notice User collateral amount for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User deposited collateral for product\n     */\n    function collateral(address account, IProduct product) public settleAccount(account, product) returns (UFixed18) {\n        return collateral().collateral(account, product);\n    }\n\n    /**\n     * @notice User maintenance amount for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return Maximum of user maintenance, and maintenanceNext\n     */\n    function maintenance(address account, IProduct product) public settleAccount(account, product) returns (UFixed18) {\n        return UFixed18Lib.max(product.maintenance(account), product.maintenanceNext(account));\n    }\n\n    /**\n     * @notice User liquidatble status for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return Whether or not the user's position eligible to be liquidated\n     */\n    function liquidatable(address account, IProduct product) public settleAccount(account, product) returns (bool) {\n        return collateral().liquidatable(account, product);\n    }\n\n    /**\n     * @notice User liquidating status for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return Whether or not the user's position is being liquidated\n     */\n    function liquidating(address account, IProduct product) public settleAccount(account, product) returns (bool) {\n        return product.isLiquidating(account);\n    }\n\n    /**\n     * @notice User pre position for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User pre-position\n     */\n    function pre(address account, IProduct product)\n        public\n        settleAccount(account, product)\n        returns (PrePosition memory)\n    {\n        return product.pre(account);\n    }\n\n    /**\n     * @notice User position for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User position\n     */\n    function position(address account, IProduct product)\n        public\n        settleAccount(account, product)\n        returns (Position memory)\n    {\n        return product.position(account);\n    }\n\n    /**\n     * @notice User pre-position and position for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User pre-position\n     * @return User position\n     */\n    function userPosition(address account, IProduct product)\n        public\n        settleAccount(account, product)\n        returns (PrePosition memory, Position memory)\n    {\n        return (product.pre(account), product.position(account));\n    }\n\n    /**\n     * @notice Fees accumulated by account after settle\n     * @param account Account address\n     * @param product Product address\n     * @return sum of all fees accrued by the account\n     */\n    function fees(address account, IProduct product) public settleAccount(account, product) returns (UFixed18) {\n        return collateral().fees(account);\n    }\n\n    /**\n     * @notice User's open interest in product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User's maker or taker position multiplied by latest price after settle\n     */\n    function openInterest(address account, IProduct product)\n        public\n        settleAccount(account, product)\n        returns (Position memory)\n    {\n        return product.position(account).mul(_latestVersion(product).price.abs());\n    }\n\n    /**\n     * @notice User's exposure in product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User's exposure (openInterest * utilization) after settle\n     */\n    function exposure(address account, IProduct product) public settleAccount(account, product) returns (UFixed18) {\n        (, Position memory _pos) = globalPosition(product);\n        if (_pos.maker.isZero()) { return UFixed18Lib.ZERO; }\n\n        Position memory _openInterest = openInterest(account, product);\n        if (!_openInterest.taker.isZero()) {\n            return _openInterest.taker; // Taker exposure is always 100% of openInterest\n        }\n\n        UFixed18 utilization = _pos.taker.div(_pos.maker);\n        return utilization.mul(_openInterest.maker); // Maker exposure is openInterest * utilization\n    }\n\n    /**\n     * @notice User's maintenance required for position size in product after settle\n     * @param account Account address\n     * @param product Product address\n     * @param positionSize size of position for maintenance calculation\n     * @return Maintenance required for position in product\n     */\n    function maintenanceRequired(\n        address account,\n        IProduct product,\n        UFixed18 positionSize\n    ) public settleAccount(account, product) returns (UFixed18) {\n        UFixed18 notional = positionSize.mul(_latestVersion(product).price.abs());\n        return notional.mul(product.maintenance());\n    }\n\n    /**\n     * @notice User's unclaimed rewards for all programs for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return tokens Token addresses of unclaimed incentive rewards for given product\n     * @return amounts Token amounts of unclaimed incentive rewards for given product\n     */\n    function unclaimedIncentiveRewards(address account, IProduct product)\n        public\n        settleAccount(account, product)\n        returns (Token18[] memory tokens, UFixed18[] memory amounts)\n    {\n        IIncentivizer incentivizer = controller.incentivizer();\n\n        uint256 programsLength = incentivizer.count(product);\n        tokens = new Token18[](programsLength);\n        amounts = new UFixed18[](programsLength);\n        for (uint256 i = 0; i < programsLength; i++) {\n            ProgramInfo memory programInfo = incentivizer.programInfos(product, i);\n            tokens[i] = programInfo.token;\n            amounts[i] = incentivizer.unclaimed(product, account, i);\n        }\n    }\n\n    /**\n     * @notice User's unclaimed rewards for provided programs for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @param programIds Program IDs to query\n     * @return tokens Token addresses of unclaimed incentive rewards for given program IDs\n     * @return amounts Token amounts of unclaimed incentive rewards for given program IDs\n     */\n    function unclaimedIncentiveRewards(\n        address account,\n        IProduct product,\n        uint256[] calldata programIds\n    ) public settleAccount(account, product) returns (Token18[] memory tokens, UFixed18[] memory amounts) {\n        IIncentivizer incentivizer = controller.incentivizer();\n        tokens = new Token18[](programIds.length);\n        amounts = new UFixed18[](programIds.length);\n        for (uint256 i = 0; i < programIds.length; i++) {\n            ProgramInfo memory programInfo = incentivizer.programInfos(product, programIds[i]);\n            tokens[i] = programInfo.token;\n            amounts[i] = incentivizer.unclaimed(product, account, programIds[i]);\n        }\n    }\n\n    /**\n     *  End UserProduct Individual Fields Functions\n     */\n\n    /**\n     *  Private Helper Functions\n     */\n\n    /**\n     * @notice Returns the Product's latest position\n     * @dev Private function, does not call settle itself\n     * @param product Product address\n     * @return Latest position for the product\n     */\n    function _latestPosition(IProduct product) private view returns (Position memory) {\n        return product.positionAtVersion(product.latestVersion());\n    }\n\n    /**\n     * @notice Returns the Product's latest version\n     * @dev Private function, does not call settle itself\n     * @param product Product address\n     * @return Latest version for the product\n     */\n    function _latestVersion(IProduct product) private view returns (IOracleProvider.OracleVersion memory) {\n        return product.atVersion(product.latestVersion());\n    }\n\n    /**\n     *  End Private Helper Functions\n     */\n\n    /**\n     *  Modifier Functions\n     */\n\n    /// @dev Settles the product\n    modifier settle(IProduct product) {\n        product.settle();\n        _;\n    }\n\n    /// @dev Settles the product. product.settleAccount also settles the product\n    modifier settleAccount(address account, IProduct product) {\n        product.settleAccount(account);\n        _;\n    }\n\n    /**\n     *  End Modifier Functions\n     */\n}\n"
    },
    "contracts/forwarder/Forwarder.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../interfaces/IForwarder.sol\";\n\n/**\n * @title Forwarder\n * @notice Facilitates collateral deposits to the protocol where the amount is supplied\n *         in USDC then wrapped as DSU before being deposited.\n */\ncontract Forwarder is IForwarder {\n    // @dev USDC stablecoin\n    Token6 public immutable USDC; // solhint-disable-line var-name-mixedcase\n\n    // @dev DSU stablecoin\n    Token18 public immutable DSU; // solhint-disable-line var-name-mixedcase\n\n    /// @dev Contract that wraps USDC to DSU\n    IBatcher public immutable batcher;\n\n    /// @dev Contract managing state for collateral accounts in the protocol\n    ICollateral public immutable collateral;\n\n    /**\n     * @notice Initializes the contract state\n     * @param usdc_ The USDC token contract address\n     * @param dsu_ The DSU token contract address\n     * @param batcher_ The USDC-to-DSU batcher contract address\n     * @param collateral_ The perennial collateral contract address\n     */\n    constructor(\n        Token6 usdc_,\n        Token18 dsu_,\n        IBatcher batcher_,\n        ICollateral collateral_\n    ) {\n        if (!Address.isContract(Token6.unwrap(usdc_))) revert ForwarderNotContractAddressError();\n        if (!Address.isContract(Token18.unwrap(dsu_))) revert ForwarderNotContractAddressError();\n        if (!Address.isContract(address(batcher_))) revert ForwarderNotContractAddressError();\n        if (!Address.isContract(address(collateral_))) revert ForwarderNotContractAddressError();\n\n        USDC = usdc_;\n        DSU = dsu_;\n        batcher = batcher_;\n        collateral = collateral_;\n\n        USDC.approve(address(batcher));\n        DSU.approve(address(collateral));\n    }\n\n    /**\n     * @notice Pulls `amount` of USDC from `msg.sender`'s balance, wraps it as DSU,\n               and deposits it as collateral to `account`'s `product` account\n     * @param account Account to deposit the collateral for\n     * @param product Product to credit the collateral to\n     * @param amount 18 decimals-normalized stablecoin (USDC, DSU) value of collateral to deposit\n    */\n    function wrapAndDeposit(\n        address account,\n        IProduct product,\n        UFixed18 amount\n    ) external {\n        USDC.pull(msg.sender, amount, true);\n        batcher.wrap(amount, address(this));\n        collateral.depositTo(account, product, amount);\n        emit WrapAndDeposit(account, product, amount);\n    }\n}\n"
    },
    "contracts/test/TestnetUSDC.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\ncontract TestnetUSDC is ERC20, ERC20Burnable {\n    // solhint-disable-next-line no-empty-blocks\n    constructor() ERC20(\"USD Coin\", \"USDC\") { }\n\n    function decimals() override public pure returns (uint8) {\n      return 6;\n    }\n\n    function mint(address account, uint256 amount) external {\n        _mint(account, amount);\n    }\n}\n"
    },
    "contracts/test/TestnetDSU.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol\";\n\ncontract TestnetDSU is ERC20, ERC20Burnable {\n    uint256 private constant LIMIT = 1_000_000e18;\n\n    address public minter;\n\n    error TestnetDSUNotMinterError();\n    error TestnetDSUOverLimitError();\n\n    event TestnetDSUMinterUpdated(address indexed newMinter);\n\n    constructor(address _minter) ERC20(\"Digital Standard Unit\", \"DSU\") {\n        minter = _minter;\n    }\n\n    function mint(address account, uint256 amount) external onlyMinter {\n        if (amount > LIMIT) revert TestnetDSUOverLimitError();\n\n        _mint(account, amount);\n    }\n\n    function updateMinter(address newMinter) external onlyMinter {\n        minter = newMinter;\n\n        emit TestnetDSUMinterUpdated(newMinter);\n    }\n\n    modifier onlyMinter() {\n        if (msg.sender != minter) revert TestnetDSUNotMinterError();\n        _;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev _Available since v3.1._\n */\ninterface IERC1155Receiver is IERC165 {\n    /**\n     * @dev Handles the receipt of a single ERC1155 token type. This function is\n     * called at the end of a `safeTransferFrom` after the balance has been updated.\n     *\n     * NOTE: To accept the transfer, this must return\n     * `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))`\n     * (i.e. 0xf23a6e61, or its own function selector).\n     *\n     * @param operator The address which initiated the transfer (i.e. msg.sender)\n     * @param from The address which previously owned the token\n     * @param id The ID of the token being transferred\n     * @param value The amount of tokens being transferred\n     * @param data Additional data with no specified format\n     * @return `bytes4(keccak256(\"onERC1155Received(address,address,uint256,uint256,bytes)\"))` if transfer is allowed\n     */\n    function onERC1155Received(\n        address operator,\n        address from,\n        uint256 id,\n        uint256 value,\n        bytes calldata data\n    ) external returns (bytes4);\n\n    /**\n     * @dev Handles the receipt of a multiple ERC1155 token types. This function\n     * is called at the end of a `safeBatchTransferFrom` after the balances have\n     * been updated.\n     *\n     * NOTE: To accept the transfer(s), this must return\n     * `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))`\n     * (i.e. 0xbc197c81, or its own function selector).\n     *\n     * @param operator The address which initiated the batch transfer (i.e. msg.sender)\n     * @param from The address which previously owned the token\n     * @param ids An array containing ids of each token being transferred (order and length must match values array)\n     * @param values An array containing amounts of each token being transferred (order and length must match ids array)\n     * @param data Additional data with no specified format\n     * @return `bytes4(keccak256(\"onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)\"))` if transfer is allowed\n     */\n    function onERC1155BatchReceived(\n        address operator,\n        address from,\n        uint256[] calldata ids,\n        uint256[] calldata values,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
    },
    "@openzeppelin/contracts/governance/TimelockController.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (governance/TimelockController.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../access/AccessControl.sol\";\nimport \"../token/ERC721/IERC721Receiver.sol\";\nimport \"../token/ERC1155/IERC1155Receiver.sol\";\n\n/**\n * @dev Contract module which acts as a timelocked controller. When set as the\n * owner of an `Ownable` smart contract, it enforces a timelock on all\n * `onlyOwner` maintenance operations. This gives time for users of the\n * controlled contract to exit before a potentially dangerous maintenance\n * operation is applied.\n *\n * By default, this contract is self administered, meaning administration tasks\n * have to go through the timelock process. The proposer (resp executor) role\n * is in charge of proposing (resp executing) operations. A common use case is\n * to position this {TimelockController} as the owner of a smart contract, with\n * a multisig or a DAO as the sole proposer.\n *\n * _Available since v3.3._\n */\ncontract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver {\n    bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256(\"TIMELOCK_ADMIN_ROLE\");\n    bytes32 public constant PROPOSER_ROLE = keccak256(\"PROPOSER_ROLE\");\n    bytes32 public constant EXECUTOR_ROLE = keccak256(\"EXECUTOR_ROLE\");\n    bytes32 public constant CANCELLER_ROLE = keccak256(\"CANCELLER_ROLE\");\n    uint256 internal constant _DONE_TIMESTAMP = uint256(1);\n\n    mapping(bytes32 => uint256) private _timestamps;\n    uint256 private _minDelay;\n\n    /**\n     * @dev Emitted when a call is scheduled as part of operation `id`.\n     */\n    event CallScheduled(\n        bytes32 indexed id,\n        uint256 indexed index,\n        address target,\n        uint256 value,\n        bytes data,\n        bytes32 predecessor,\n        uint256 delay\n    );\n\n    /**\n     * @dev Emitted when a call is performed as part of operation `id`.\n     */\n    event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data);\n\n    /**\n     * @dev Emitted when operation `id` is cancelled.\n     */\n    event Cancelled(bytes32 indexed id);\n\n    /**\n     * @dev Emitted when the minimum delay for future operations is modified.\n     */\n    event MinDelayChange(uint256 oldDuration, uint256 newDuration);\n\n    /**\n     * @dev Initializes the contract with a given `minDelay`, and a list of\n     * initial proposers and executors. The proposers receive both the\n     * proposer and the canceller role (for backward compatibility). The\n     * executors receive the executor role.\n     *\n     * NOTE: At construction, both the deployer and the timelock itself are\n     * administrators. This helps further configuration of the timelock by the\n     * deployer. After configuration is done, it is recommended that the\n     * deployer renounces its admin position and relies on timelocked\n     * operations to perform future maintenance.\n     */\n    constructor(\n        uint256 minDelay,\n        address[] memory proposers,\n        address[] memory executors\n    ) {\n        _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE);\n        _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE);\n        _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE);\n        _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE);\n\n        // deployer + self administration\n        _setupRole(TIMELOCK_ADMIN_ROLE, _msgSender());\n        _setupRole(TIMELOCK_ADMIN_ROLE, address(this));\n\n        // register proposers and cancellers\n        for (uint256 i = 0; i < proposers.length; ++i) {\n            _setupRole(PROPOSER_ROLE, proposers[i]);\n            _setupRole(CANCELLER_ROLE, proposers[i]);\n        }\n\n        // register executors\n        for (uint256 i = 0; i < executors.length; ++i) {\n            _setupRole(EXECUTOR_ROLE, executors[i]);\n        }\n\n        _minDelay = minDelay;\n        emit MinDelayChange(0, minDelay);\n    }\n\n    /**\n     * @dev Modifier to make a function callable only by a certain role. In\n     * addition to checking the sender's role, `address(0)` 's role is also\n     * considered. Granting a role to `address(0)` is equivalent to enabling\n     * this role for everyone.\n     */\n    modifier onlyRoleOrOpenRole(bytes32 role) {\n        if (!hasRole(role, address(0))) {\n            _checkRole(role, _msgSender());\n        }\n        _;\n    }\n\n    /**\n     * @dev Contract might receive/hold ETH as part of the maintenance process.\n     */\n    receive() external payable {}\n\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, AccessControl) returns (bool) {\n        return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);\n    }\n\n    /**\n     * @dev Returns whether an id correspond to a registered operation. This\n     * includes both Pending, Ready and Done operations.\n     */\n    function isOperation(bytes32 id) public view virtual returns (bool pending) {\n        return getTimestamp(id) > 0;\n    }\n\n    /**\n     * @dev Returns whether an operation is pending or not.\n     */\n    function isOperationPending(bytes32 id) public view virtual returns (bool pending) {\n        return getTimestamp(id) > _DONE_TIMESTAMP;\n    }\n\n    /**\n     * @dev Returns whether an operation is ready or not.\n     */\n    function isOperationReady(bytes32 id) public view virtual returns (bool ready) {\n        uint256 timestamp = getTimestamp(id);\n        return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp;\n    }\n\n    /**\n     * @dev Returns whether an operation is done or not.\n     */\n    function isOperationDone(bytes32 id) public view virtual returns (bool done) {\n        return getTimestamp(id) == _DONE_TIMESTAMP;\n    }\n\n    /**\n     * @dev Returns the timestamp at with an operation becomes ready (0 for\n     * unset operations, 1 for done operations).\n     */\n    function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) {\n        return _timestamps[id];\n    }\n\n    /**\n     * @dev Returns the minimum delay for an operation to become valid.\n     *\n     * This value can be changed by executing an operation that calls `updateDelay`.\n     */\n    function getMinDelay() public view virtual returns (uint256 duration) {\n        return _minDelay;\n    }\n\n    /**\n     * @dev Returns the identifier of an operation containing a single\n     * transaction.\n     */\n    function hashOperation(\n        address target,\n        uint256 value,\n        bytes calldata data,\n        bytes32 predecessor,\n        bytes32 salt\n    ) public pure virtual returns (bytes32 hash) {\n        return keccak256(abi.encode(target, value, data, predecessor, salt));\n    }\n\n    /**\n     * @dev Returns the identifier of an operation containing a batch of\n     * transactions.\n     */\n    function hashOperationBatch(\n        address[] calldata targets,\n        uint256[] calldata values,\n        bytes[] calldata payloads,\n        bytes32 predecessor,\n        bytes32 salt\n    ) public pure virtual returns (bytes32 hash) {\n        return keccak256(abi.encode(targets, values, payloads, predecessor, salt));\n    }\n\n    /**\n     * @dev Schedule an operation containing a single transaction.\n     *\n     * Emits a {CallScheduled} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have the 'proposer' role.\n     */\n    function schedule(\n        address target,\n        uint256 value,\n        bytes calldata data,\n        bytes32 predecessor,\n        bytes32 salt,\n        uint256 delay\n    ) public virtual onlyRole(PROPOSER_ROLE) {\n        bytes32 id = hashOperation(target, value, data, predecessor, salt);\n        _schedule(id, delay);\n        emit CallScheduled(id, 0, target, value, data, predecessor, delay);\n    }\n\n    /**\n     * @dev Schedule an operation containing a batch of transactions.\n     *\n     * Emits one {CallScheduled} event per transaction in the batch.\n     *\n     * Requirements:\n     *\n     * - the caller must have the 'proposer' role.\n     */\n    function scheduleBatch(\n        address[] calldata targets,\n        uint256[] calldata values,\n        bytes[] calldata payloads,\n        bytes32 predecessor,\n        bytes32 salt,\n        uint256 delay\n    ) public virtual onlyRole(PROPOSER_ROLE) {\n        require(targets.length == values.length, \"TimelockController: length mismatch\");\n        require(targets.length == payloads.length, \"TimelockController: length mismatch\");\n\n        bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);\n        _schedule(id, delay);\n        for (uint256 i = 0; i < targets.length; ++i) {\n            emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay);\n        }\n    }\n\n    /**\n     * @dev Schedule an operation that is to becomes valid after a given delay.\n     */\n    function _schedule(bytes32 id, uint256 delay) private {\n        require(!isOperation(id), \"TimelockController: operation already scheduled\");\n        require(delay >= getMinDelay(), \"TimelockController: insufficient delay\");\n        _timestamps[id] = block.timestamp + delay;\n    }\n\n    /**\n     * @dev Cancel an operation.\n     *\n     * Requirements:\n     *\n     * - the caller must have the 'canceller' role.\n     */\n    function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) {\n        require(isOperationPending(id), \"TimelockController: operation cannot be cancelled\");\n        delete _timestamps[id];\n\n        emit Cancelled(id);\n    }\n\n    /**\n     * @dev Execute an (ready) operation containing a single transaction.\n     *\n     * Emits a {CallExecuted} event.\n     *\n     * Requirements:\n     *\n     * - the caller must have the 'executor' role.\n     */\n    // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending,\n    // thus any modifications to the operation during reentrancy should be caught.\n    // slither-disable-next-line reentrancy-eth\n    function execute(\n        address target,\n        uint256 value,\n        bytes calldata data,\n        bytes32 predecessor,\n        bytes32 salt\n    ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) {\n        bytes32 id = hashOperation(target, value, data, predecessor, salt);\n        _beforeCall(id, predecessor);\n        _call(id, 0, target, value, data);\n        _afterCall(id);\n    }\n\n    /**\n     * @dev Execute an (ready) operation containing a batch of transactions.\n     *\n     * Emits one {CallExecuted} event per transaction in the batch.\n     *\n     * Requirements:\n     *\n     * - the caller must have the 'executor' role.\n     */\n    function executeBatch(\n        address[] calldata targets,\n        uint256[] calldata values,\n        bytes[] calldata payloads,\n        bytes32 predecessor,\n        bytes32 salt\n    ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) {\n        require(targets.length == values.length, \"TimelockController: length mismatch\");\n        require(targets.length == payloads.length, \"TimelockController: length mismatch\");\n\n        bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt);\n        _beforeCall(id, predecessor);\n        for (uint256 i = 0; i < targets.length; ++i) {\n            _call(id, i, targets[i], values[i], payloads[i]);\n        }\n        _afterCall(id);\n    }\n\n    /**\n     * @dev Checks before execution of an operation's calls.\n     */\n    function _beforeCall(bytes32 id, bytes32 predecessor) private view {\n        require(isOperationReady(id), \"TimelockController: operation is not ready\");\n        require(predecessor == bytes32(0) || isOperationDone(predecessor), \"TimelockController: missing dependency\");\n    }\n\n    /**\n     * @dev Checks after execution of an operation's calls.\n     */\n    function _afterCall(bytes32 id) private {\n        require(isOperationReady(id), \"TimelockController: operation is not ready\");\n        _timestamps[id] = _DONE_TIMESTAMP;\n    }\n\n    /**\n     * @dev Execute an operation's call.\n     *\n     * Emits a {CallExecuted} event.\n     */\n    function _call(\n        bytes32 id,\n        uint256 index,\n        address target,\n        uint256 value,\n        bytes calldata data\n    ) private {\n        (bool success, ) = target.call{value: value}(data);\n        require(success, \"TimelockController: underlying transaction reverted\");\n\n        emit CallExecuted(id, index, target, value, data);\n    }\n\n    /**\n     * @dev Changes the minimum timelock duration for future operations.\n     *\n     * Emits a {MinDelayChange} event.\n     *\n     * Requirements:\n     *\n     * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing\n     * an operation where the timelock is the target and the data is the ABI-encoded call to this function.\n     */\n    function updateDelay(uint256 newDelay) external virtual {\n        require(msg.sender == address(this), \"TimelockController: caller must be timelock\");\n        emit MinDelayChange(_minDelay, newDelay);\n        _minDelay = newDelay;\n    }\n\n    /**\n     * @dev See {IERC721Receiver-onERC721Received}.\n     */\n    function onERC721Received(\n        address,\n        address,\n        uint256,\n        bytes memory\n    ) public virtual override returns (bytes4) {\n        return this.onERC721Received.selector;\n    }\n\n    /**\n     * @dev See {IERC1155Receiver-onERC1155Received}.\n     */\n    function onERC1155Received(\n        address,\n        address,\n        uint256,\n        uint256,\n        bytes memory\n    ) public virtual override returns (bytes4) {\n        return this.onERC1155Received.selector;\n    }\n\n    /**\n     * @dev See {IERC1155Receiver-onERC1155BatchReceived}.\n     */\n    function onERC1155BatchReceived(\n        address,\n        address,\n        uint256[] memory,\n        uint256[] memory,\n        bytes memory\n    ) public virtual override returns (bytes4) {\n        return this.onERC1155BatchReceived.selector;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721Receiver {\n    /**\n     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n     * by `operator` from `from`, this function is called.\n     *\n     * It must return its Solidity selector to confirm the token transfer.\n     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n     *\n     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n     */\n    function onERC721Received(\n        address operator,\n        address from,\n        uint256 tokenId,\n        bytes calldata data\n    ) external returns (bytes4);\n}\n"
    },
    "contracts/hardhat-dependency-compiler/@openzeppelin/contracts/governance/TimelockController.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@openzeppelin/contracts/governance/TimelockController.sol';\n"
    },
    "contracts/hardhat-dependency-compiler/@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol';\n"
    },
    "contracts/hardhat-dependency-compiler/@equilibria/emptyset-batcher/batcher/Batcher.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@equilibria/emptyset-batcher/batcher/Batcher.sol';\n"
    },
    "contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol';\n"
    },
    "contracts/hardhat-dependency-compiler/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol';\n"
    },
    "@equilibria/perennial-oracle/contracts/ReservoirFeedOracle.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\nimport \"./interfaces/IOracleProvider.sol\";\n\n/**\n * @title ReservoirFeedOracle\n * @notice Reservoir implementation of the IOracle interface, using Reservoir's AggregatorV3Interface adaptors\n * @dev This is a naive implementation which pushes all validation to the underlying. No staleness checks are possible\n        This oracle should not be used for regular Chainlink Data Feeds\n */\ncontract ReservoirFeedOracle is IOracleProvider {\n    error InvalidOracleVersion();\n\n    /// @dev Chainlink price feed to read from\n    AggregatorV3Interface public immutable feed;\n\n    /// @dev Decimal offset used to normalize chainlink price to 18 decimals\n    int256 private immutable _decimalOffset;\n\n    /// @dev Which underlying round to consider version 0: version = roundId - _versionOffset\n    uint80 private immutable _versionOffset;\n\n    /**\n     * @notice Initializes the contract state\n     * @param feed_ Reservoir price feed\n     * @param versionOffset_ Version offset from source round ID\n     */\n    constructor(AggregatorV3Interface feed_, uint80 versionOffset_) {\n        feed = feed_;\n        _versionOffset = versionOffset_;\n        _decimalOffset = SafeCast.toInt256(10 ** feed_.decimals());\n    }\n\n    /**\n     * @notice Checks for a new price. Does not perform staleness validation as the underlying oracle does not\n                support this.\n     * @return The current oracle version after sync\n     */\n    function sync() external view returns (OracleVersion memory) {\n        (uint80 roundId, int256 feedPrice, , uint256 timestamp,) = feed.latestRoundData();\n\n        return _buildOracleVersion(roundId, feedPrice, timestamp);\n    }\n\n    /**\n     * @notice Returns the current oracle version\n     * @return oracleVersion Current oracle version\n     */\n    function currentVersion() public view returns (OracleVersion memory oracleVersion) {\n        (uint80 roundId, int256 feedPrice, , uint256 timestamp,) = feed.latestRoundData();\n\n        return _buildOracleVersion(roundId, feedPrice, timestamp);\n    }\n\n    /**\n     * @notice Returns the oracle version specified\n     * @dev Converts the passed in version to a roundID by adding _versionOffset\n     * @param version The version of which to lookup\n     * @return oracleVersion Oracle version at version `version`\n     */\n    function atVersion(uint256 version) public view returns (OracleVersion memory oracleVersion) {\n        // To convert from version to roundId, we add the versionOffset\n        uint256 feedRoundID = version + _versionOffset;\n        if (feedRoundID > type(uint80).max) revert InvalidOracleVersion();\n        (uint80 roundId, int256 feedPrice, , uint256 timestamp,) = feed.getRoundData(uint80(feedRoundID));\n\n        return _buildOracleVersion(roundId, feedPrice, timestamp);\n    }\n\n    /**\n     * @notice Builds an oracle version object from a Chainlink round object\n     * @dev Converts the passed in roundID to a version by subtracting _versionOffset\n     * @param roundId ReservoirRoundId round to build from\n     * @param feedPrice price returns by the oracle\n     * @param timestamp round timestamps\n     * @return Built oracle version\n     */\n    function _buildOracleVersion(uint80 roundId, int256 feedPrice, uint256 timestamp)\n    private view returns (OracleVersion memory) {\n        Fixed18 price = Fixed18Lib.ratio(feedPrice, _decimalOffset);\n\n        // To convert from roundId to version, we subtract the versionOffset\n        return OracleVersion({ version: roundId - _versionOffset, timestamp: timestamp, price: price });\n    }\n}\n"
    },
    "@openzeppelin/contracts/utils/math/SafeCast.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits.\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128) {\n        require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return int128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64) {\n        require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return int64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32) {\n        require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return int32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16) {\n        require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return int16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits.\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8) {\n        require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return int8(value);\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"
    },
    "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n\n  function description() external view returns (string memory);\n\n  function version() external view returns (uint256);\n\n  // getRoundData and latestRoundData should both raise \"No data present\"\n  // if they do not have data to report, instead of returning unset values\n  // which could be misinterpreted as actual reported values.\n  function getRoundData(uint80 _roundId)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  function latestRoundData()\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n}\n"
    },
    "@equilibria/perennial-oracle/contracts/test/PassthroughDataFeed.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\ncontract PassthroughDataFeed {\n    AggregatorV3Interface private _underlying;\n\n    constructor(AggregatorV3Interface underlying_) {\n        _underlying = underlying_;\n    }\n\n    function decimals() external view returns (uint8) {\n        return _underlying.decimals();\n    }\n\n    function getRoundData(uint80 roundId) external view returns (uint80, int256, uint256, uint256, uint80) {\n        return _underlying.getRoundData(roundId);\n    }\n\n    function latestRoundData() external view returns (uint80, int256, uint256, uint256, uint80) {\n        return _underlying.latestRoundData();\n    }\n}\n"
    },
    "contracts/hardhat-dependency-compiler/@equilibria/perennial-oracle/contracts/test/PassthroughDataFeed.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@equilibria/perennial-oracle/contracts/test/PassthroughDataFeed.sol';\n"
    },
    "@equilibria/perennial-oracle/contracts/types/ChainlinkRound.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol\";\n\n/// @dev ChainlinkRound type\nstruct ChainlinkRound {\n    uint256 timestamp;\n    int256 answer;\n    uint80 roundId;\n}\nusing ChainlinkRoundLib for ChainlinkRound global;\n\n/**\n * @title ChainlinkRoundLib\n * @notice Library that manages Chainlink round parsing.\n */\nlibrary ChainlinkRoundLib {\n    /// @dev Phase ID offset location in the round ID\n    uint256 constant private PHASE_OFFSET = 64;\n\n    /**\n     * @notice Computes the chainlink phase ID from a round\n     * @param self Round to compute from\n     * @return Chainlink phase ID\n     */\n    function phaseId(ChainlinkRound memory self) internal pure returns (uint16) {\n        return uint16(self.roundId >> PHASE_OFFSET);\n    }\n}\n"
    },
    "@equilibria/perennial-oracle/contracts/types/ChainlinkRegistry.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol\";\nimport \"./ChainlinkRound.sol\";\n\n/// @dev ChainlinkRegistry type\ntype ChainlinkRegistry is address;\nusing ChainlinkRegistryLib for ChainlinkRegistry global;\n\n/**\n * @title ChainlinkRegistryLib\n * @notice Library that manages interfacing with the Chainlink Feed Registry.\n */\nlibrary ChainlinkRegistryLib {\n    /**\n     * @notice Returns the decimal amount for a specific feed\n     * @param self Chainlink Feed Registry to operate on\n     * @param base Base currency token address\n     * @param quote Quote currency token address\n     * @return Decimal amount\n     */\n    function decimals(ChainlinkRegistry self, address base, address quote) internal view returns (uint8) {\n        return FeedRegistryInterface(ChainlinkRegistry.unwrap(self)).decimals(base, quote);\n    }\n\n    /**\n     * @notice Returns the latest round data for a specific feed\n     * @param self Chainlink Feed Registry to operate on\n     * @param base Base currency token address\n     * @param quote Quote currency token address\n     * @return Latest round data\n     */\n    function getLatestRound(ChainlinkRegistry self, address base, address quote) internal view returns (ChainlinkRound memory) {\n        (uint80 roundId, int256 answer, , uint256 updatedAt, ) =\n            FeedRegistryInterface(ChainlinkRegistry.unwrap(self)).latestRoundData(base, quote);\n        return ChainlinkRound({roundId: roundId, timestamp: updatedAt, answer: answer});\n    }\n\n    /**\n     * @notice Returns a specific round's data for a specific feed\n     * @param self Chainlink Feed Registry to operate on\n     * @param base Base currency token address\n     * @param quote Quote currency token address\n     * @param roundId The specific round to fetch data for\n     * @return Specific round's data\n     */\n    function getRound(ChainlinkRegistry self, address base, address quote, uint80 roundId) internal view returns (ChainlinkRound memory) {\n        (, int256 answer, , uint256 updatedAt, ) =\n            FeedRegistryInterface(ChainlinkRegistry.unwrap(self)).getRoundData(base, quote, roundId);\n        return ChainlinkRound({roundId: roundId, timestamp: updatedAt, answer: answer});\n    }\n\n\n    /**\n     * @notice Returns the first round ID for a specific phase ID\n     * @param self Chainlink Feed Registry to operate on\n     * @param base Base currency token address\n     * @param quote Quote currency token address\n     * @param phaseId The specific phase to fetch data for\n     * @return startingRoundId The starting round ID for the phase\n     */\n    function getStartingRoundId(ChainlinkRegistry self, address base, address quote, uint16 phaseId)\n    internal view returns (uint80 startingRoundId) {\n        (startingRoundId, ) =\n            FeedRegistryInterface(ChainlinkRegistry.unwrap(self)).getPhaseRange(base, quote, phaseId);\n    }\n\n    /**\n     * @notice Returns the quantity of rounds for a specific phase ID\n     * @param self Chainlink Feed Registry to operate on\n     * @param base Base currency token address\n     * @param quote Quote currency token address\n     * @param phaseId The specific phase to fetch data for\n     * @return The quantity of rounds for the phase\n     */\n    function getRoundCount(ChainlinkRegistry self, address base, address quote, uint16 phaseId)\n    internal view returns (uint80) {\n        (uint80 startingRoundId, uint80 endingRoundId) =\n            FeedRegistryInterface(ChainlinkRegistry.unwrap(self)).getPhaseRange(base, quote, phaseId);\n        return endingRoundId - startingRoundId + 1;\n    }\n}\n"
    },
    "@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\npragma abicoder v2;\n\nimport \"./AggregatorV2V3Interface.sol\";\n\ninterface FeedRegistryInterface {\n  struct Phase {\n    uint16 phaseId;\n    uint80 startingAggregatorRoundId;\n    uint80 endingAggregatorRoundId;\n  }\n\n  event FeedProposed(\n    address indexed asset,\n    address indexed denomination,\n    address indexed proposedAggregator,\n    address currentAggregator,\n    address sender\n  );\n  event FeedConfirmed(\n    address indexed asset,\n    address indexed denomination,\n    address indexed latestAggregator,\n    address previousAggregator,\n    uint16 nextPhaseId,\n    address sender\n  );\n\n  // V3 AggregatorV3Interface\n\n  function decimals(address base, address quote) external view returns (uint8);\n\n  function description(address base, address quote) external view returns (string memory);\n\n  function version(address base, address quote) external view returns (uint256);\n\n  function latestRoundData(address base, address quote)\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  function getRoundData(\n    address base,\n    address quote,\n    uint80 _roundId\n  )\n    external\n    view\n    returns (\n      uint80 roundId,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  // V2 AggregatorInterface\n\n  function latestAnswer(address base, address quote) external view returns (int256 answer);\n\n  function latestTimestamp(address base, address quote) external view returns (uint256 timestamp);\n\n  function latestRound(address base, address quote) external view returns (uint256 roundId);\n\n  function getAnswer(\n    address base,\n    address quote,\n    uint256 roundId\n  ) external view returns (int256 answer);\n\n  function getTimestamp(\n    address base,\n    address quote,\n    uint256 roundId\n  ) external view returns (uint256 timestamp);\n\n  // Registry getters\n\n  function getFeed(address base, address quote) external view returns (AggregatorV2V3Interface aggregator);\n\n  function getPhaseFeed(\n    address base,\n    address quote,\n    uint16 phaseId\n  ) external view returns (AggregatorV2V3Interface aggregator);\n\n  function isFeedEnabled(address aggregator) external view returns (bool);\n\n  function getPhase(\n    address base,\n    address quote,\n    uint16 phaseId\n  ) external view returns (Phase memory phase);\n\n  // Round helpers\n\n  function getRoundFeed(\n    address base,\n    address quote,\n    uint80 roundId\n  ) external view returns (AggregatorV2V3Interface aggregator);\n\n  function getPhaseRange(\n    address base,\n    address quote,\n    uint16 phaseId\n  ) external view returns (uint80 startingRoundId, uint80 endingRoundId);\n\n  function getPreviousRoundId(\n    address base,\n    address quote,\n    uint80 roundId\n  ) external view returns (uint80 previousRoundId);\n\n  function getNextRoundId(\n    address base,\n    address quote,\n    uint80 roundId\n  ) external view returns (uint80 nextRoundId);\n\n  // Feed management\n\n  function proposeFeed(\n    address base,\n    address quote,\n    address aggregator\n  ) external;\n\n  function confirmFeed(\n    address base,\n    address quote,\n    address aggregator\n  ) external;\n\n  // Proposed aggregator\n\n  function getProposedFeed(address base, address quote)\n    external\n    view\n    returns (AggregatorV2V3Interface proposedAggregator);\n\n  function proposedGetRoundData(\n    address base,\n    address quote,\n    uint80 roundId\n  )\n    external\n    view\n    returns (\n      uint80 id,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  function proposedLatestRoundData(address base, address quote)\n    external\n    view\n    returns (\n      uint80 id,\n      int256 answer,\n      uint256 startedAt,\n      uint256 updatedAt,\n      uint80 answeredInRound\n    );\n\n  // Phases\n  function getCurrentPhaseId(address base, address quote) external view returns (uint16 currentPhaseId);\n}\n"
    },
    "@chainlink/contracts/src/v0.8/interfaces/AggregatorV2V3Interface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./AggregatorInterface.sol\";\nimport \"./AggregatorV3Interface.sol\";\n\ninterface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}\n"
    },
    "@chainlink/contracts/src/v0.8/interfaces/AggregatorInterface.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface AggregatorInterface {\n  function latestAnswer() external view returns (int256);\n\n  function latestTimestamp() external view returns (uint256);\n\n  function latestRound() external view returns (uint256);\n\n  function getAnswer(uint256 roundId) external view returns (int256);\n\n  function getTimestamp(uint256 roundId) external view returns (uint256);\n\n  event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);\n\n  event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);\n}\n"
    },
    "@equilibria/perennial-oracle/contracts/test/PassthroughChainlinkFeed.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol\";\n\ncontract PassthroughChainlinkFeed {\n    FeedRegistryInterface private _underlying;\n\n    constructor(FeedRegistryInterface underlying_) {\n        _underlying = underlying_;\n    }\n\n    function decimals(address base, address quote) external view returns (uint8) {\n        return _underlying.decimals(base, quote);\n    }\n\n    function getRoundData(address base, address quote, uint80 roundId) external view returns (uint80, int256, uint256, uint256, uint80) {\n        return _underlying.getRoundData(base, quote, roundId);\n    }\n\n    function getPhaseRange(address base, address quote, uint16 phaseId) external view returns (uint80, uint80) {\n        return _underlying.getPhaseRange(base, quote, phaseId);\n    }\n\n    function latestRoundData(address base, address quote) external view returns (uint80, int256, uint256, uint256, uint80) {\n        return _underlying.latestRoundData(base, quote);\n    }\n}\n"
    },
    "contracts/hardhat-dependency-compiler/@equilibria/perennial-oracle/contracts/test/PassthroughChainlinkFeed.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@equilibria/perennial-oracle/contracts/test/PassthroughChainlinkFeed.sol';\n"
    },
    "@equilibria/perennial-oracle/contracts/ChainlinkOracle.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@chainlink/contracts/src/v0.8/interfaces/FeedRegistryInterface.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\nimport \"./interfaces/IOracleProvider.sol\";\nimport \"./types/ChainlinkRegistry.sol\";\n\n/**\n * @title ChainlinkOracle\n * @notice Chainlink implementation of the IOracle interface.\n * @dev One instance per Chainlink price feed should be deployed. Multiple products may use the same\n *      ChainlinkOracle instance if their payoff functions are based on the same underlying oracle.\n *      This implementation only support non-negative prices.\n */\ncontract ChainlinkOracle is IOracleProvider {\n    /// @dev Chainlink registry feed address\n    ChainlinkRegistry public immutable registry;\n\n    /// @dev Base token address for the Chainlink oracle\n    address public immutable base;\n\n    /// @dev Quote token address for the Chainlink oracle\n    address public immutable quote;\n\n    /// @dev Decimal offset used to normalize chainlink price to 18 decimals\n    int256 private immutable _decimalOffset;\n\n    /// @dev Mapping of the first oracle version for each underlying phase ID\n    uint256[] private _startingVersionForPhaseId;\n\n    /**\n     * @notice Initializes the contract state\n     * @param registry_ Chainlink price feed registry\n     * @param base_ base currency for feed\n     * @param quote_ quote currency for feed\n     */\n    constructor(ChainlinkRegistry registry_, address base_, address quote_) {\n        registry = registry_;\n        base = base_;\n        quote = quote_;\n\n        _startingVersionForPhaseId.push(0); // phaseId is 1-indexed, skip index 0\n        _startingVersionForPhaseId.push(0); // phaseId is 1-indexed, first phase starts as version 0\n        _decimalOffset = SafeCast.toInt256(10 ** registry_.decimals(base, quote));\n    }\n\n    /**\n     * @notice Checks for a new price and updates the internal phase annotation state accordingly\n     * @return The current oracle version after sync\n     */\n    function sync() external returns (OracleVersion memory) {\n        // Fetch latest round\n        ChainlinkRound memory round = registry.getLatestRound(base, quote);\n\n        // Update phase annotation when new phase detected\n        while (round.phaseId() > _latestPhaseId()) {\n            uint256 roundCount = registry.getRoundCount(base, quote, _latestPhaseId());\n            _startingVersionForPhaseId.push(roundCount);\n        }\n\n        // Return packaged oracle version\n        return _buildOracleVersion(round);\n    }\n\n    /**\n     * @notice Returns the current oracle version\n     * @return oracleVersion Current oracle version\n     */\n    function currentVersion() public view returns (OracleVersion memory oracleVersion) {\n        return _buildOracleVersion(registry.getLatestRound(base, quote));\n    }\n\n    /**\n     * @notice Returns the current oracle version\n     * @param version The version of which to lookup\n     * @return oracleVersion Oracle version at version `version`\n     */\n    function atVersion(uint256 version) public view returns (OracleVersion memory oracleVersion) {\n        return _buildOracleVersion(registry.getRound(base, quote, _versionToRoundId(version)), version);\n    }\n\n    /**\n     * @notice Builds an oracle version object from a Chainlink round object\n     * @dev Computes the version for the round\n     * @param round Chainlink round to build from\n     * @return Built oracle version\n     */\n    function _buildOracleVersion(ChainlinkRound memory round) private view returns (OracleVersion memory) {\n        uint256 version = _startingVersionForPhaseId[round.phaseId()] +\n            uint256(round.roundId - registry.getStartingRoundId(base, quote, round.phaseId()));\n        return _buildOracleVersion(round, version);\n    }\n\n    /**\n     * @notice Builds an oracle version object from a Chainlink round object\n     * @param round Chainlink round to build from\n     * @param version Determined version for the round\n     * @return Built oracle version\n     */\n    function _buildOracleVersion(ChainlinkRound memory round, uint256 version)\n    private view returns (OracleVersion memory) {\n        Fixed18 price = Fixed18Lib.ratio(round.answer, _decimalOffset);\n        return OracleVersion({ version: version, timestamp: round.timestamp, price: price });\n    }\n\n    /**\n     * @notice Computes the chainlink round ID from a version\n     * @notice version Version to compute from\n     * @return Chainlink round ID\n     */\n    function _versionToRoundId(uint256 version) private view returns (uint80) {\n        uint16 phaseId = _versionToPhaseId(version);\n        return registry.getStartingRoundId(base, quote, phaseId) +\n            uint80(version - _startingVersionForPhaseId[phaseId]);\n    }\n\n    /**\n     * @notice Computes the chainlink phase ID from a version\n     * @param version Version to compute from\n     * @return phaseId Chainlink phase ID\n     */\n    function _versionToPhaseId(uint256 version) private view returns (uint16 phaseId) {\n        phaseId = _latestPhaseId();\n        while (_startingVersionForPhaseId[phaseId] > version) {\n            phaseId--;\n        }\n    }\n\n    /**\n     * @notice Returns the latest phase ID that this contract has seen via `sync()`\n     * @return Latest seen phase ID\n     */\n    function _latestPhaseId() private view returns (uint16) {\n        return uint16(_startingVersionForPhaseId.length - 1);\n    }\n}\n"
    },
    "contracts/hardhat-dependency-compiler/@equilibria/perennial-oracle/contracts/ChainlinkOracle.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@equilibria/perennial-oracle/contracts/ChainlinkOracle.sol';\n"
    },
    "contracts/hardhat-dependency-compiler/@equilibria/perennial-oracle/contracts/ReservoirFeedOracle.sol": {
      "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity >0.0.0;\nimport '@equilibria/perennial-oracle/contracts/ReservoirFeedOracle.sol';\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 1000000
    },
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "storageLayout",
          "evm.gasEstimates"
        ],
        "": ["ast"]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}
