{
  "language": "Solidity",
  "sources": {
    "contracts/product/Product.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 \"../controller/UControllerProvider.sol\";\nimport \"./UPayoffProvider.sol\";\nimport \"./UParamProvider.sol\";\nimport \"./types/position/AccountPosition.sol\";\nimport \"./types/accumulator/AccountAccumulator.sol\";\n\n/**\n * @title Product\n * @notice Manages logic and state for a single product market.\n * @dev Cloned by the Controller contract to launch new product markets.\n */\ncontract Product is IProduct, UInitializable, UParamProvider, UPayoffProvider, UReentrancyGuard {\n    /// @dev Whether or not the product is closed\n    BoolStorage private constant _closed =\n        BoolStorage.wrap(keccak256(\"equilibria.perennial.Product.closed\"));\n    function closed() public view returns (bool) { return _closed.read(); }\n\n\n    /// @dev The name of the product\n    string public name;\n\n    /// @dev The symbol of the product\n    string public symbol;\n\n    /// @dev The individual position state for each account\n    mapping(address => AccountPosition) private _positions;\n\n    /// @dev The global position state for the product\n    VersionedPosition private _position;\n\n    /// @dev The individual accumulator state for each account\n    mapping(address => AccountAccumulator) private _accumulators;\n\n    /// @dev The global accumulator state for the product\n    VersionedAccumulator private _accumulator;\n\n    /**\n     * @notice Initializes the contract state\n     * @param productInfo_ Product initialization params\n     */\n    function initialize(ProductInfo calldata productInfo_) external initializer(1) {\n        __UControllerProvider__initialize(IController(msg.sender));\n        __UPayoffProvider__initialize(productInfo_.oracle, productInfo_.payoffDefinition);\n        __UReentrancyGuard__initialize();\n        __UParamProvider__initialize(\n            productInfo_.maintenance,\n            productInfo_.fundingFee,\n            productInfo_.makerFee,\n            productInfo_.takerFee,\n            productInfo_.makerLimit,\n            productInfo_.utilizationCurve\n        );\n\n        name = productInfo_.name;\n        symbol = productInfo_.symbol;\n    }\n\n    /**\n     * @notice Surfaces global settlement externally\n     */\n    function settle() external nonReentrant notPaused {\n        _settle();\n    }\n\n    /**\n     * @notice Core global settlement flywheel\n     * @dev\n     *  a) last settle oracle version\n     *  b) latest pre position oracle version\n     *  c) current oracle version\n     *\n     *  Settles from a->b then from b->c if either interval is non-zero to account for a change\n     *  in position quantity at (b).\n     *\n     *  Syncs each to instantaneously after the oracle update.\n     */\n    function _settle() private returns (IOracleProvider.OracleVersion memory currentOracleVersion) {\n        IController _controller = controller();\n\n        // Get current oracle version\n        currentOracleVersion = _sync();\n\n        // Get latest oracle version\n        uint256 _latestVersion = latestVersion();\n        if (_latestVersion == currentOracleVersion.version) return currentOracleVersion; // short circuit entirely if a == c\n        IOracleProvider.OracleVersion memory latestOracleVersion = atVersion(_latestVersion);\n\n        // Get settle oracle version\n        uint256 _settleVersion = _position.pre.settleVersion(currentOracleVersion.version);\n        IOracleProvider.OracleVersion memory settleOracleVersion = _settleVersion == currentOracleVersion.version ?\n            currentOracleVersion : // if b == c, don't re-call provider for oracle version\n            atVersion(_settleVersion);\n\n        // Initiate\n        _controller.incentivizer().sync(currentOracleVersion);\n        UFixed18 boundedFundingFee = _boundedFundingFee();\n        UFixed18 accumulatedFee;\n\n        // value a->b\n        accumulatedFee = accumulatedFee.add(\n            _accumulator.accumulate(boundedFundingFee, _position, latestOracleVersion, settleOracleVersion)\n        );\n\n        // position a->b\n        accumulatedFee = accumulatedFee.add(_position.settle(_latestVersion, settleOracleVersion));\n\n        // short-circuit from a->c if b == c\n        if (settleOracleVersion.version != currentOracleVersion.version) {\n\n            // value b->c\n            accumulatedFee = accumulatedFee.add(\n                _accumulator.accumulate(boundedFundingFee, _position, settleOracleVersion, currentOracleVersion)\n            );\n\n            // position b->c (every accumulator version needs a position stamp)\n            _position.settle(settleOracleVersion.version, currentOracleVersion);\n        }\n\n        // settle collateral\n        _controller.collateral().settleProduct(accumulatedFee);\n\n        emit Settle(settleOracleVersion.version, currentOracleVersion.version);\n    }\n\n    /**\n     * @notice Surfaces account settlement externally\n     * @param account Account to settle\n     */\n    function settleAccount(address account) external nonReentrant notPaused {\n        IOracleProvider.OracleVersion memory currentOracleVersion = _settle();\n        _settleAccount(account, currentOracleVersion);\n    }\n\n    /**\n     * @notice Core account settlement flywheel\n     * @param account Account to settle\n     * @dev\n     *  a) last settle oracle version\n     *  b) latest pre position oracle version\n     *  c) current oracle version\n     *\n     *  Settles from a->b then from b->c if either interval is non-zero to account for a change\n     *  in position quantity at (b).\n     *\n     *  Syncs each to instantaneously after the oracle update.\n     */\n    function _settleAccount(address account, IOracleProvider.OracleVersion memory currentOracleVersion) private {\n        IController _controller = controller();\n\n        // Get latest oracle version\n        if (latestVersion(account) == currentOracleVersion.version) return; // short circuit entirely if a == c\n\n        // Get settle oracle version\n        uint256 _settleVersion = _positions[account].pre.settleVersion(currentOracleVersion.version);\n        IOracleProvider.OracleVersion memory settleOracleVersion = _settleVersion == currentOracleVersion.version ?\n            currentOracleVersion : // if b == c, don't re-call provider for oracle version\n            atVersion(_settleVersion);\n\n        // initialize\n        Fixed18 accumulated;\n\n        // sync incentivizer before accumulator\n        _controller.incentivizer().syncAccount(account, settleOracleVersion);\n\n        // value a->b\n        accumulated = accumulated.add(\n            _accumulators[account].syncTo(_accumulator, _positions[account], settleOracleVersion.version).sum());\n\n        // position a->b\n        accumulated = accumulated.sub(Fixed18Lib.from(_positions[account].settle(settleOracleVersion)));\n\n        // short-circuit from a->c if b == c\n        if (settleOracleVersion.version != currentOracleVersion.version) {\n            // sync incentivizer before accumulator\n            _controller.incentivizer().syncAccount(account, currentOracleVersion);\n\n            // value b->c\n            accumulated = accumulated.add(\n                _accumulators[account].syncTo(_accumulator, _positions[account], currentOracleVersion.version).sum());\n        }\n\n        // settle collateral\n        _controller.collateral().settleAccount(account, accumulated);\n\n        emit AccountSettle(account, settleOracleVersion.version, currentOracleVersion.version);\n    }\n\n    /**\n     * @notice Opens a taker position for `msg.sender`\n     * @param amount Amount of the position to open\n     */\n    function openTake(UFixed18 amount)\n    external\n    nonReentrant\n    notPaused\n    notClosed\n    settleForAccount(msg.sender)\n    takerInvariant\n    positionInvariant\n    liquidationInvariant\n    maintenanceInvariant\n    {\n        uint256 _latestVersion = latestVersion();\n\n        _positions[msg.sender].pre.openTake(_latestVersion, amount);\n        _position.pre.openTake(_latestVersion, amount);\n\n        emit TakeOpened(msg.sender, _latestVersion, amount);\n    }\n\n    /**\n     * @notice Closes a taker position for `msg.sender`\n     * @param amount Amount of the position to close\n     */\n    function closeTake(UFixed18 amount)\n    external\n    nonReentrant\n    notPaused\n    settleForAccount(msg.sender)\n    closeInvariant\n    liquidationInvariant\n    {\n        _closeTake(msg.sender, amount);\n    }\n\n    function _closeTake(address account, UFixed18 amount) private {\n        uint256 _latestVersion = latestVersion();\n\n        _positions[account].pre.closeTake(_latestVersion, amount);\n        _position.pre.closeTake(_latestVersion, amount);\n\n        emit TakeClosed(account, _latestVersion, amount);\n    }\n\n    /**\n     * @notice Opens a maker position for `msg.sender`\n     * @param amount Amount of the position to open\n     */\n    function openMake(UFixed18 amount)\n    external\n    nonReentrant\n    notPaused\n    notClosed\n    settleForAccount(msg.sender)\n    nonZeroVersionInvariant\n    makerInvariant\n    positionInvariant\n    liquidationInvariant\n    maintenanceInvariant\n    {\n        uint256 _latestVersion = latestVersion();\n\n        _positions[msg.sender].pre.openMake(_latestVersion, amount);\n        _position.pre.openMake(_latestVersion, amount);\n\n        emit MakeOpened(msg.sender, _latestVersion, amount);\n    }\n\n    /**\n     * @notice Closes a maker position for `msg.sender`\n     * @param amount Amount of the position to close\n     */\n    function closeMake(UFixed18 amount)\n    external\n    nonReentrant\n    notPaused\n    settleForAccount(msg.sender)\n    takerInvariant\n    closeInvariant\n    liquidationInvariant\n    {\n        _closeMake(msg.sender, amount);\n    }\n\n    function _closeMake(address account, UFixed18 amount) private {\n        uint256 _latestVersion = latestVersion();\n\n        _positions[account].pre.closeMake(_latestVersion, amount);\n        _position.pre.closeMake(_latestVersion, amount);\n\n        emit MakeClosed(account, _latestVersion, amount);\n    }\n\n    /**\n     * @notice Closes all open and pending positions, locking for liquidation\n     * @dev Only callable by the Collateral contract as part of the liquidation flow\n     * @param account Account to close out\n     */\n    function closeAll(address account) external onlyCollateral notClosed settleForAccount(account) {\n        AccountPosition storage accountPosition = _positions[account];\n        Position memory p = accountPosition.position.next(_positions[account].pre);\n\n        // Close all positions\n        _closeMake(account, p.maker);\n        _closeTake(account, p.taker);\n\n        // Mark liquidation to lock position\n        accountPosition.liquidation = true;\n    }\n\n    /**\n     * @notice Returns the maintenance requirement for `account`\n     * @param account Account to return for\n     * @return The current maintenance requirement\n     */\n    function maintenance(address account) external view returns (UFixed18) {\n        return _positions[account].maintenance();\n    }\n\n    /**\n     * @notice Returns the maintenance requirement for `account` after next settlement\n     * @dev Assumes no price change and no funding, used to protect user from over-opening\n     * @param account Account to return for\n     * @return The next maintenance requirement\n     */\n    function maintenanceNext(address account) external view returns (UFixed18) {\n        return _positions[account].maintenanceNext();\n    }\n\n    /**\n     * @notice Returns whether `account` has a completely zero'd position\n     * @param account Account to return for\n     * @return The the account is closed\n     */\n    function isClosed(address account) external view returns (bool) {\n        return _positions[account].isClosed();\n    }\n\n    /**\n     * @notice Returns whether `account` is currently locked for an in-progress liquidation\n     * @param account Account to return for\n     * @return Whether the account is in liquidation\n     */\n    function isLiquidating(address account) external view returns (bool) {\n        return _positions[account].liquidation;\n    }\n\n    /**\n     * @notice Returns `account`'s current position\n     * @param account Account to return for\n     * @return Current position of the account\n     */\n    function position(address account) external view returns (Position memory) {\n        return _positions[account].position;\n    }\n\n    /**\n     * @notice Returns `account`'s current pending-settlement position\n     * @param account Account to return for\n     * @return Current pre-position of the account\n     */\n    function pre(address account) external view returns (PrePosition memory) {\n        return _positions[account].pre;\n    }\n\n    /**\n     * @notice Returns the global latest settled oracle version\n     * @return Latest settled oracle version of the product\n     */\n    function latestVersion() public view returns (uint256) {\n        return _accumulator.latestVersion;\n    }\n\n    /**\n     * @notice Returns the global position at oracleVersion `oracleVersion`\n     * @dev Only valid for the version at which a global settlement occurred\n     * @param oracleVersion Oracle version to return for\n     * @return Global position at oracle version\n     */\n    function positionAtVersion(uint256 oracleVersion) public view returns (Position memory) {\n        return _position.positionAtVersion(oracleVersion);\n    }\n\n    /**\n     * @notice Returns the current global pending-settlement position\n     * @return Global pending-settlement position\n     */\n    function pre() external view returns (PrePosition memory) {\n        return _position.pre;\n    }\n\n    /**\n     * @notice Returns the global accumulator value at oracleVersion `oracleVersion`\n     * @dev Only valid for the version at which a global settlement occurred\n     * @param oracleVersion Oracle version to return for\n     * @return Global accumulator value at oracle version\n     */\n    function valueAtVersion(uint256 oracleVersion) external view returns (Accumulator memory) {\n        return _accumulator.valueAtVersion(oracleVersion);\n    }\n\n    /**\n     * @notice Returns the global accumulator share at oracleVersion `oracleVersion`\n     * @dev Only valid for the version at which a global settlement occurred\n     * @param oracleVersion Oracle version to return for\n     * @return Global accumulator share at oracle version\n     */\n    function shareAtVersion(uint256 oracleVersion) external view returns (Accumulator memory) {\n        return _accumulator.shareAtVersion(oracleVersion);\n    }\n\n    /**\n     * @notice Returns `account`'s latest settled oracle version\n     * @param account Account to return for\n     * @return Latest settled oracle version of the account\n     */\n    function latestVersion(address account) public view returns (uint256) {\n        return _accumulators[account].latestVersion;\n    }\n\n    /**\n     * @notice Returns The per-second rate based on the provided `position`\n     * @dev Handles 0-maker/taker edge cases\n     * @param position_ Position to base utilization on\n     * @return The per-second rate\n     */\n    function rate(Position calldata position_) public view returns (Fixed18) {\n        UFixed18 utilization = position_.taker.unsafeDiv(position_.maker);\n        Fixed18 annualizedRate = utilizationCurve().compute(utilization);\n        return annualizedRate.div(Fixed18Lib.from(365 days));\n    }\n\n    /**\n     * @notice Returns the minimum funding fee parameter with a capped range for safety\n     * @dev Caps controller.minFundingFee() <= fundingFee() <= 1\n     * @return Safe minimum funding fee parameter\n     */\n    function _boundedFundingFee() private view returns (UFixed18) {\n        return fundingFee().max(controller().minFundingFee());\n    }\n\n    /**\n     * @notice Updates product closed state\n     * @dev only callable by product owner. Settles the product before flipping the flag\n     * @param newClosed new closed value\n     */\n    function updateClosed(bool newClosed) external onlyProductOwner {\n        IOracleProvider.OracleVersion memory oracleVersion = _settle();\n        _closed.store(newClosed);\n        emit ClosedUpdated(newClosed, oracleVersion.version);\n    }\n\n    /// @dev Limit total maker for guarded rollouts\n    modifier makerInvariant {\n        _;\n\n        Position memory next = positionAtVersion(latestVersion()).next(_position.pre);\n\n        if (next.maker.gt(makerLimit())) revert ProductMakerOverLimitError();\n    }\n\n    /// @dev Limit maker short exposure to the range 0.0-1.0x of their position. Does not apply when in closeOnly state\n    modifier takerInvariant {\n        _;\n\n        if (closed()) return;\n\n        Position memory next = positionAtVersion(latestVersion()).next(_position.pre);\n        UFixed18 socializationFactor = next.socializationFactor();\n\n        if (socializationFactor.lt(UFixed18Lib.ONE)) revert ProductInsufficientLiquidityError(socializationFactor);\n    }\n\n    /// @dev Ensure that the user has only taken a maker or taker position, but not both\n    modifier positionInvariant {\n        _;\n\n        if (_positions[msg.sender].isDoubleSided()) revert ProductDoubleSidedError();\n    }\n\n    /// @dev Ensure that the user hasn't closed more than is open\n    modifier closeInvariant {\n        _;\n\n        if (_positions[msg.sender].isOverClosed()) revert ProductOverClosedError();\n    }\n\n    /// @dev Ensure that the user will have sufficient margin for maintenance after next settlement\n    modifier maintenanceInvariant {\n        _;\n\n        if (controller().collateral().liquidatableNext(msg.sender, IProduct(this)))\n            revert ProductInsufficientCollateralError();\n    }\n\n    /// @dev Ensure that the user is not currently being liquidated\n    modifier liquidationInvariant {\n        if (_positions[msg.sender].liquidation) revert ProductInLiquidationError();\n\n        _;\n    }\n\n    /// @dev Helper to fully settle an account's state\n    modifier settleForAccount(address account) {\n        IOracleProvider.OracleVersion memory _currentVersion = _settle();\n        _settleAccount(account, _currentVersion);\n\n        _;\n    }\n\n    /// @dev Ensure we have bootstraped the oracle before creating positions\n    modifier nonZeroVersionInvariant {\n        if (latestVersion() == 0) revert ProductOracleBootstrappingError();\n\n        _;\n    }\n\n    /// @dev Ensure the product is not closed\n    modifier notClosed {\n        if (closed()) revert ProductClosedError();\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/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"
    },
    "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"
    },
    "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/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/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"
    },
    "@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"
    },
    "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/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/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/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/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"
    },
    "@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"
    },
    "@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/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/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/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/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/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"
    },
    "@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"
    },
    "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/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"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 5800
    },
    "outputSelection": {
      "*": {
        "*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata"],
        "": ["ast"]
      }
    }
  }
}
