{
  "language": "Solidity",
  "sources": {
    "contracts/lens/PerennialLens.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"../interfaces/IPerennialLens.sol\";\n\n/**\n * @title Lens contract to conveniently pull protocol data\n * @notice All functions should be called using `callStatic`\n */\ncontract PerennialLens is IPerennialLens {\n    /**\n     * @notice Protocol controller\n     * @return Protocol controller\n     */\n    IController public immutable controller;\n\n    /// @param _controller Protocol controller address\n    constructor(IController _controller) {\n        controller = _controller;\n    }\n\n    /**\n     * @notice Returns the name of the provided `product`\n     * @param product Product address\n     * @return Name of the product\n     */\n    function name(IProduct product) external view returns (string memory) {\n        return product.name();\n    }\n\n    /**\n     * @notice Returns the symbol of the provided `product`\n     * @param product Product address\n     * @return Symbol of the product\n     */\n    function symbol(IProduct product) external view returns (string memory) {\n        return product.symbol();\n    }\n\n    /**\n     * @notice Protocol collateral address\n     * @return Protocol collateral address\n     */\n    function collateral() public view returns (ICollateral) {\n        return controller.collateral();\n    }\n\n    /**\n     * @notice User collateral amount for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User deposited collateral for product\n     */\n    function collateral(address account, IProduct product) external settleAccount(account, product) returns (UFixed18) {\n        return collateral().collateral(account, product);\n    }\n\n    /**\n     * @notice Product total collateral amount after settle\n     * @param product Product address\n     * @return Total collateral for product\n     */\n    function collateral(IProduct product) external settle(product) returns (UFixed18) {\n        return collateral().collateral(product);\n    }\n\n    /**\n     * @notice Product total shortfall amount after settle\n     * @param product Product address\n     * @return Total shortfall for product\n     */\n    function shortfall(IProduct product) external settle(product) returns (UFixed18) {\n        return collateral().shortfall(product);\n    }\n\n    /**\n     * @notice User maintenance amount for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return Maximum of user maintenance, and maintenanceNext\n     */\n    function maintenance(address account, IProduct product)\n        external\n        settleAccount(account, product)\n        returns (UFixed18)\n    {\n        return UFixed18Lib.max(product.maintenance(account), product.maintenanceNext(account));\n    }\n\n    /**\n     * @notice User liquidatble status for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return Whether or not the user's position eligible to be liquidated\n     */\n    function liquidatable(address account, IProduct product) external settleAccount(account, product) returns (bool) {\n        return collateral().liquidatable(account, product);\n    }\n\n    /**\n     * @notice User pre position for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User pre-position\n     */\n    function pre(address account, IProduct product)\n        external\n        settleAccount(account, product)\n        returns (PrePosition memory)\n    {\n        return product.pre(account);\n    }\n\n    /**\n     * @notice Product pre position after settle\n     * @param product Product address\n     * @return Product pre-position\n     */\n    function pre(IProduct product) external settle(product) returns (PrePosition memory) {\n        return product.pre();\n    }\n\n    /**\n     * @notice User position for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User position\n     */\n    function position(address account, IProduct product)\n        external\n        settleAccount(account, product)\n        returns (Position memory)\n    {\n        return product.position(account);\n    }\n\n    /**\n     * @notice Product position after settle\n     * @param product Product address\n     * @return product position\n     */\n    function position(IProduct product) external settle(product) returns (Position memory) {\n        return _latestPosition(product);\n    }\n\n    /**\n     * @notice User pre-position and position for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User pre-position\n     * @return User position\n     */\n    function userPosition(address account, IProduct product)\n        external\n        settleAccount(account, product)\n        returns (PrePosition memory, Position memory)\n    {\n        return (product.pre(account), product.position(account));\n    }\n\n    /**\n     * @notice Product pre-position and position after settle\n     * @param product Product address\n     * @return Product pre-position\n     * @return Product position\n     */\n    function globalPosition(IProduct product) external settle(product) returns (PrePosition memory, Position memory) {\n        return (product.pre(), _latestPosition(product));\n    }\n\n    /**\n     * @notice Current price of product after settle\n     * @param product Product address\n     * @return Product latest price\n     */\n    function price(IProduct product) external settle(product) returns (Fixed18) {\n        return _latestVersion(product).price;\n    }\n\n    /**\n     * @notice Current price of product at specified version after settle\n     * @param product Product address\n     * @param version Oracle version\n     * @return Product price at specified version\n     */\n    function priceAtVersion(IProduct product, uint version) external settle(product) returns (Fixed18) {\n        return product.atVersion(version).price;\n    }\n\n    /**\n     * @notice Prices of product at specified versions after settle\n     * @param product Product address\n     * @param versions Oracle versions to query\n     * @return prices Product prices at specified versions\n     */\n    function pricesAtVersions(IProduct product, uint[] memory versions)\n    external settle(product) returns (Fixed18[] memory prices) {\n        prices = new Fixed18[](versions.length);\n        for (uint256 i = 0; i < versions.length; i++) {\n            prices[i] = product.atVersion(versions[i]).price;\n        }\n    }\n\n    /**\n     * @notice Fees accumulated by product and protocol treasuries after settle\n     * @param product Product address\n     * @return protocolFees fees accrued by the protocol\n     * @return productFees fees accrued by the product owner\n     */\n    function fees(IProduct product) external settle(product) returns (UFixed18 protocolFees, UFixed18 productFees) {\n        address protocolTreasury = controller.treasury();\n        address productTreasury = controller.treasury(product);\n\n        protocolFees = collateral().fees(protocolTreasury);\n        productFees = collateral().fees(productTreasury);\n    }\n\n    /**\n     * @notice Fees accumulated by treasury after settle\n     * @param account Account address\n     * @param products Product addresses\n     * @return sum of all fees accrued by the account\n     */\n    function fees(address account, IProduct[] memory products) external returns (UFixed18) {\n        for (uint256 i = 0; i < products.length; i++) {\n            products[i].settle();\n        }\n\n        return collateral().fees(account);\n    }\n\n    /**\n     * @notice User's open interest in product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return User's maker or taker position multiplied by latest price after settle\n     */\n    function openInterest(address account, IProduct product)\n        external\n        settleAccount(account, product)\n        returns (Position memory)\n    {\n        return product.position(account).mul(_latestVersion(product).price.abs());\n    }\n\n    /**\n     * @notice Product total open interest after settle\n     * @param product Product address\n     * @return Product maker and taker position multiplied by latest price after settle\n     */\n    function openInterest(IProduct product) external settle(product) returns (Position memory) {\n        return _latestPosition(product).mul(_latestVersion(product).price.abs());\n    }\n\n    /**\n     * @notice Product funding rate after settle\n     * @param product Product address\n     * @return Product current funding rate\n     */\n    function rate(IProduct product) external settle(product) returns (Fixed18) {\n        Position memory position_ = _latestPosition(product);\n        return product.rate(position_);\n    }\n\n    /**\n     * @notice Product funding extrapolated to a daily rate after settle\n     * @param product Product address\n     * @return Product current funding extrapolated to a daily rate\n     */\n    function dailyRate(IProduct product) external settle(product) returns (Fixed18) {\n        Position memory position_ = _latestPosition(product);\n        return product.rate(position_).mul(Fixed18Lib.from(60 * 60 * 24));\n    }\n\n    /**\n     * @notice User's maintenance required for position size in product after settle\n     * @param account Account address\n     * @param product Product address\n     * @param positionSize size of position for maintenance calculation\n     * @return Maintenance required for position in product\n     */\n    function maintenanceRequired(\n        address account,\n        IProduct product,\n        UFixed18 positionSize\n    ) external settleAccount(account, product) returns (UFixed18) {\n        UFixed18 notional = positionSize.mul(_latestVersion(product).price.abs());\n        return notional.mul(product.maintenance());\n    }\n\n    /**\n     * @notice User's unclaimed rewards for all programs for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @return tokens Token addresses of unclaimed incentive rewards for given product\n     * @return amounts Token amounts of unclaimed incentive rewards for given product\n     */\n    function unclaimedIncentiveRewards(address account, IProduct product)\n        external\n        settleAccount(account, product)\n        returns (Token18[] memory tokens, UFixed18[] memory amounts)\n    {\n        IIncentivizer incentivizer = controller.incentivizer();\n\n        uint256 programsLength = incentivizer.count(product);\n        tokens = new Token18[](programsLength);\n        amounts = new UFixed18[](programsLength);\n        for (uint256 i = 0; i < programsLength; i++) {\n            ProgramInfo memory programInfo = incentivizer.programInfos(product, i);\n            tokens[i] = programInfo.token;\n            amounts[i] = incentivizer.unclaimed(product, account, i);\n        }\n    }\n\n    /**\n     * @notice User's unclaimed rewards for provided programs for product after settle\n     * @param account Account address\n     * @param product Product address\n     * @param programIds Program IDs to query\n     * @return tokens Token addresses of unclaimed incentive rewards for given program IDs\n     * @return amounts Token amounts of unclaimed incentive rewards for given program IDs\n     */\n    function unclaimedIncentiveRewards(\n        address account,\n        IProduct product,\n        uint256[] calldata programIds\n    ) external settleAccount(account, product) returns (Token18[] memory tokens, UFixed18[] memory amounts) {\n        IIncentivizer incentivizer = controller.incentivizer();\n        tokens = new Token18[](programIds.length);\n        amounts = new UFixed18[](programIds.length);\n        for (uint256 i = 0; i < programIds.length; i++) {\n            ProgramInfo memory programInfo = incentivizer.programInfos(product, programIds[i]);\n            tokens[i] = programInfo.token;\n            amounts[i] = incentivizer.unclaimed(product, account, programIds[i]);\n        }\n    }\n\n    // TODO: all data for Product, all data for User, batching\n\n    /**\n     * @notice Returns the Product's latest position\n     * @dev Private function, does not call settle itself\n     * @param product Product address\n     * @return Latest position for the product\n     */\n    function _latestPosition(IProduct product) private view returns (Position memory) {\n        return product.positionAtVersion(product.latestVersion());\n    }\n\n    /**\n     * @notice Returns the Product's latest version\n     * @dev Private function, does not call settle itself\n     * @param product Product address\n     * @return Latest version for the product\n     */\n    function _latestVersion(IProduct product) private view returns (IOracleProvider.OracleVersion memory) {\n        return product.currentVersion();\n    }\n\n    /// @dev Settles the product\n    modifier settle(IProduct product) {\n        product.settle();\n        _;\n    }\n\n    /// @dev Settles the product. product.settleAccount also settles the product\n    modifier settleAccount(address account, IProduct product) {\n        product.settleAccount(account);\n        _;\n    }\n}\n"
    },
    "contracts/interfaces/IPerennialLens.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.15;\n\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./IProduct.sol\";\nimport \"./ICollateral.sol\";\nimport \"./IController.sol\";\n\ninterface IPerennialLens {\n    function controller() external view returns (IController);\n    function name(IProduct product) external view returns (string memory);\n    function symbol(IProduct product) external view returns (string memory);\n    function collateral() external view returns (ICollateral);\n    function collateral(address account, IProduct product) external returns (UFixed18);\n    function collateral(IProduct product) external returns (UFixed18);\n    function shortfall(IProduct product) external returns (UFixed18);\n    function maintenance(address account, IProduct product) external returns (UFixed18);\n    function liquidatable(address account, IProduct product) external returns (bool);\n    function pre(address account, IProduct product) external returns (PrePosition memory);\n    function pre(IProduct product) external returns (PrePosition memory);\n    function position(address account, IProduct product) external returns (Position memory);\n    function position(IProduct product) external returns (Position memory);\n    function userPosition(address account, IProduct product) external returns (PrePosition memory, Position memory);\n    function globalPosition(IProduct product) external returns (PrePosition memory, Position memory);\n    function price(IProduct product) external returns (Fixed18);\n    function fees(IProduct product) external returns (UFixed18 protocolFees, UFixed18 productFees);\n    function fees(address account, IProduct[] memory products) external returns (UFixed18);\n    function openInterest(address account, IProduct product) external returns (Position memory);\n    function openInterest(IProduct product) external returns (Position memory);\n    function rate(IProduct product) external returns (Fixed18);\n    function dailyRate(IProduct product) external returns (Fixed18);\n    function maintenanceRequired(\n        address account,\n        IProduct product,\n        UFixed18 positionSize\n    ) external returns (UFixed18);\n    function unclaimedIncentiveRewards(address account, IProduct product)\n        external\n        returns (Token18[] memory tokens, UFixed18[] memory amounts);\n    function unclaimedIncentiveRewards(\n        address account,\n        IProduct product,\n        uint256[] calldata programIds\n    ) external returns (Token18[] memory tokens, UFixed18[] memory amounts);\n}\n"
    },
    "@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/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"
    },
    "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/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"
    },
    "@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"
    },
    "@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/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"
    },
    "@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"
    },
    "@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/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"
    },
    "@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/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"
    },
    "contracts/interfaces/types/Position.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@openzeppelin/contracts/utils/math/Math.sol\";\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"../IProduct.sol\";\nimport \"./Accumulator.sol\";\nimport \"./PrePosition.sol\";\nimport \"./PackedPosition.sol\";\n\n/// @dev Position type\nstruct Position {\n    /// @dev Quantity of the maker position\n    UFixed18 maker;\n    /// @dev Quantity of the taker position\n    UFixed18 taker;\n}\nusing PositionLib for Position global;\n\n/**\n * @title PositionLib\n * @notice Library that surfaces math and settlement computations for the Position type.\n * @dev Positions track the current quantity of the account's maker and taker positions respectively\n *      denominated as a unit of the product's payoff function.\n */\nlibrary PositionLib {\n    /**\n     * @notice Creates a packed position from an position\n     * @param self A position\n     * @return New packed position\n     */\n    function pack(Position memory self) internal pure returns (PackedPosition memory) {\n        return PackedPosition({maker: self.maker.pack(), taker: self.taker.pack()});\n    }\n\n    /**\n     * @notice Returns whether the position is fully empty\n     * @param self A position\n     * @return Whether the position is empty\n     */\n    function isEmpty(Position memory self) internal pure returns (bool) {\n        return self.maker.isZero() && self.taker.isZero();\n    }\n\n    /**\n     * @notice Adds position `a` and `b` together, returning the result\n     * @param a The first position to sum\n     * @param b The second position to sum\n     * @return Resulting summed position\n     */\n    function add(Position memory a, Position memory b) internal pure returns (Position memory) {\n        return Position({maker: a.maker.add(b.maker), taker: a.taker.add(b.taker)});\n    }\n\n    /**\n     * @notice Subtracts position `b` from `a`, returning the result\n     * @param a The position to subtract from\n     * @param b The position to subtract\n     * @return Resulting subtracted position\n     */\n    function sub(Position memory a, Position memory b) internal pure returns (Position memory) {\n        return Position({maker: a.maker.sub(b.maker), taker: a.taker.sub(b.taker)});\n    }\n\n    /**\n     * @notice Multiplies position `self` by accumulator `accumulator` and returns the resulting accumulator\n     * @param self The Position to operate on\n     * @param accumulator The accumulator to multiply by\n     * @return Resulting multiplied accumulator\n     */\n    function mul(Position memory self, Accumulator memory accumulator) internal pure returns (Accumulator memory) {\n        return Accumulator({\n            maker: Fixed18Lib.from(self.maker).mul(accumulator.maker),\n            taker: Fixed18Lib.from(self.taker).mul(accumulator.taker)\n        });\n    }\n\n    /**\n     * @notice Scales position `self` by fixed-decimal `scale` and returns the resulting position\n     * @param self The Position to operate on\n     * @param scale The Fixed-decimal to scale by\n     * @return Resulting scaled position\n     */\n    function mul(Position memory self, UFixed18 scale) internal pure returns (Position memory) {\n        return Position({maker: self.maker.mul(scale), taker: self.taker.mul(scale)});\n    }\n\n    /**\n     * @notice Divides position `self` by `b` and returns the resulting accumulator\n     * @param self The Position to operate on\n     * @param b The number to divide by\n     * @return Resulting divided accumulator\n     */\n    function div(Position memory self, uint256 b) internal pure returns (Accumulator memory) {\n        return Accumulator({\n            maker: Fixed18Lib.from(self.maker).div(Fixed18Lib.from(UFixed18Lib.from(b))),\n            taker: Fixed18Lib.from(self.taker).div(Fixed18Lib.from(UFixed18Lib.from(b)))\n        });\n    }\n\n    /**\n     * @notice Returns the maximum of `self`'s maker and taker values\n     * @param self The struct to operate on\n     * @return Resulting maximum value\n     */\n    function max(Position memory self) internal pure returns (UFixed18) {\n        return UFixed18Lib.max(self.maker, self.taker);\n    }\n\n    /**\n     * @notice Sums the maker and taker together from a single position\n     * @param self The struct to operate on\n     * @return The sum of its maker and taker\n     */\n    function sum(Position memory self) internal pure returns (UFixed18) {\n        return self.maker.add(self.taker);\n    }\n\n    /**\n     * @notice Computes the next position after the pending-settlement position delta is included\n     * @param self The current Position\n     * @param pre The pending-settlement position delta\n     * @return Next Position\n     */\n    function next(Position memory self, PrePosition memory pre) internal pure returns (Position memory) {\n        return sub(add(self, pre.openPosition), pre.closePosition);\n    }\n\n    /**\n     * @notice Returns the settled position at oracle version `toOracleVersion`\n     * @dev Checks if a new position is ready to be settled based on the provided `toOracleVersion`\n     *      and `pre` and returns accordingly\n     * @param self The current Position\n     * @param pre The pending-settlement position delta\n     * @param toOracleVersion The oracle version to settle to\n     * @return Settled position at oracle version\n     * @return Fee accrued from opening or closing the position\n     * @return Whether a new position was settled\n     */\n    function settled(\n        Position memory self,\n        PrePosition memory pre,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal view returns (Position memory, UFixed18, bool) {\n        return pre.canSettle(toOracleVersion) ? (next(self, pre), pre.computeFee(toOracleVersion), true) : (self, UFixed18Lib.ZERO, false);\n    }\n\n    /**\n     * @notice Returns the socialization factor for the current position\n     * @dev Socialization account for the case where `taker` > `maker` temporarily due to a liquidation\n     *      on the maker side. This dampens the taker's exposure pro-rata to ensure that the maker side\n     *      is never exposed over 1 x short.\n     * @param self The Position to operate on\n     * @return Socialization factor\n     */\n    function socializationFactor(Position memory self) internal pure returns (UFixed18) {\n        return self.taker.isZero() ? UFixed18Lib.ONE : UFixed18Lib.min(UFixed18Lib.ONE, self.maker.div(self.taker));\n    }\n}\n"
    },
    "contracts/interfaces/types/PrePosition.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./Position.sol\";\nimport \"../IProduct.sol\";\n\n/// @dev PrePosition type\nstruct PrePosition {\n    /// @dev Oracle version at which the new position delta was recorded\n    uint256 oracleVersion;\n\n    /// @dev Size of position to open at oracle version\n    Position openPosition;\n\n    /// @dev Size of position to close at oracle version\n    Position closePosition;\n}\nusing PrePositionLib for PrePosition global;\n\n/**\n * @title PrePositionLib\n * @notice Library that manages a pre-settlement position delta.\n * @dev PrePositions track the currently awaiting-settlement deltas to a settled Position. These are\n *      Primarily necessary to introduce lag into the settlement system such that oracle lag cannot be\n *      gamed to a user's advantage. When a user opens or closes a new position, it sits as a PrePosition\n *      for one oracle version until it's settle into the Position, making it then effective. PrePositions\n *      are automatically settled at the correct oracle version even if a flywheel call doesn't happen until\n *      several version into the future by using the historical version lookups in the corresponding \"Versioned\"\n *      global state types.\n */\nlibrary PrePositionLib {\n    /**\n     * @notice Returns whether there is no pending-settlement position delta\n     * @dev Can be \"empty\" even with a non-zero oracleVersion if a position is opened and\n     *      closed in the same version netting out to a zero position delta\n     * @param self The struct to operate on\n     * @return Whether the pending-settlement position delta is empty\n     */\n    function isEmpty(PrePosition memory self) internal pure returns (bool) {\n        return self.openPosition.isEmpty() && self.closePosition.isEmpty();\n    }\n\n    /**\n     * @notice Increments the maker side of the open position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The position amount to open\n     */\n    function openMake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.openPosition.maker = self.openPosition.maker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netMake(self);\n    }\n\n    /**\n     * @notice Increments the maker side of the close position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The maker position amount to close\n     */\n    function closeMake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.closePosition.maker = self.closePosition.maker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netMake(self);\n    }\n\n    /**\n     * @notice Increments the taker side of the open position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The taker position amount to open\n     */\n    function openTake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.openPosition.taker = self.openPosition.taker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netTake(self);\n    }\n\n    /**\n     * @notice Increments the taker side of the close position delta\n     * @dev Nets out open and close deltas to minimize the size of each\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @param amount The taker position amount to close\n     */\n    function closeTake(PrePosition storage self, uint256 currentVersion, UFixed18 amount) internal {\n        self.closePosition.taker = self.closePosition.taker.add(amount);\n        self.oracleVersion = currentVersion;\n        _netTake(self);\n    }\n\n    /**\n     * @notice Nets out the open and close on the maker side of the position delta\n     * @param self The struct to operate on\n     */\n    function _netMake(PrePosition storage self) private {\n        if (self.openPosition.maker.gt(self.closePosition.maker)) {\n            self.openPosition.maker = self.openPosition.maker.sub(self.closePosition.maker);\n            self.closePosition.maker = UFixed18Lib.ZERO;\n        } else {\n            self.closePosition.maker = self.closePosition.maker.sub(self.openPosition.maker);\n            self.openPosition.maker = UFixed18Lib.ZERO;\n        }\n    }\n\n    /**\n     * @notice Nets out the open and close on the taker side of the position delta\n     * @param self The struct to operate on\n     */\n    function _netTake(PrePosition storage self) private {\n        if (self.openPosition.taker.gt(self.closePosition.taker)) {\n            self.openPosition.taker = self.openPosition.taker.sub(self.closePosition.taker);\n            self.closePosition.taker = UFixed18Lib.ZERO;\n        } else {\n            self.closePosition.taker = self.closePosition.taker.sub(self.openPosition.taker);\n            self.openPosition.taker = UFixed18Lib.ZERO;\n        }\n    }\n\n    /**\n     * @notice Returns whether the the pending position delta can be settled at version `toOracleVersion`\n     * @dev Pending-settlement positions deltas can be settled (1) oracle version after they are recorded\n     * @param self The struct to operate on\n     * @param toOracleVersion The potential oracle version to settle\n     * @return Whether the position delta can be settled\n     */\n    function canSettle(\n        PrePosition memory self,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal pure returns (bool) {\n        return !isEmpty(self) && toOracleVersion.version > self.oracleVersion;\n    }\n\n    /**\n     * @notice Computes the fee incurred for opening or closing the pending-settlement position\n     * @dev Must be called from a valid product to get the proper fee amounts\n     * @param self The struct to operate on\n     * @param toOracleVersion The oracle version at which settlement takes place\n     * @return positionFee The maker / taker fee incurred\n     */\n    function computeFee(\n        PrePosition memory self,\n        IOracleProvider.OracleVersion memory toOracleVersion\n    ) internal view returns (UFixed18) {\n        Position memory positionDelta = self.openPosition.add(self.closePosition);\n\n        (UFixed18 makerNotional, UFixed18 takerNotional) = (\n            Fixed18Lib.from(positionDelta.maker).mul(toOracleVersion.price).abs(),\n            Fixed18Lib.from(positionDelta.taker).mul(toOracleVersion.price).abs()\n        );\n\n        IProduct product = IProduct(address(this));\n        return makerNotional.mul(product.makerFee()).add(takerNotional.mul(product.takerFee()));\n    }\n\n    /**\n     * @notice Computes the next oracle version to settle\n     * @dev - If there is no pending-settlement position delta, returns the current oracle version\n     *      - Otherwise returns the oracle version at which the pending-settlement position delta can be first settled\n     *\n     *      Corresponds to point (b) in the Position settlement flow\n     * @param self The struct to operate on\n     * @param currentVersion The current oracle version index\n     * @return Next oracle version to settle\n     */\n    function settleVersion(PrePosition storage self, uint256 currentVersion) internal view returns (uint256) {\n        uint256 _oracleVersion = self.oracleVersion;\n        return _oracleVersion == 0 ? currentVersion : _oracleVersion + 1;\n    }\n}\n"
    },
    "contracts/interfaces/types/Accumulator.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/number/types/Fixed18.sol\";\nimport \"./PackedAccumulator.sol\";\n\n/// @dev Accumulator type\nstruct Accumulator {\n    /// @dev maker accumulator per share\n    Fixed18 maker;\n    /// @dev taker accumulator per share\n    Fixed18 taker;\n}\nusing AccumulatorLib for Accumulator global;\n\n/**\n * @title AccountAccumulatorLib\n * @notice Library that surfaces math operations for the Accumulator type.\n * @dev Accumulators track the cumulative change in position value over time for the maker and taker positions\n *      respectively. Account-level accumulators can then use two of these values `a` and `a'` to compute the\n *      change in position value since last sync. This change in value is then used to compute P&L and fees.\n */\nlibrary AccumulatorLib {\n    /**\n     * @notice Creates a packed accumulator from an accumulator\n     * @param self an accumulator\n     * @return New packed accumulator\n     */\n    function pack(Accumulator memory self) internal pure returns (PackedAccumulator memory) {\n        return PackedAccumulator({maker: self.maker.pack(), taker: self.taker.pack()});\n    }\n\n    /**\n     * @notice Adds two accumulators together\n     * @param a The first accumulator to sum\n     * @param b The second accumulator to sum\n     * @return The resulting summed accumulator\n     */\n    function add(Accumulator memory a, Accumulator memory b) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: a.maker.add(b.maker), taker: a.taker.add(b.taker)});\n    }\n\n    /**\n     * @notice Subtracts accumulator `b` from `a`\n     * @param a The accumulator to subtract from\n     * @param b The accumulator to subtract\n     * @return The resulting subtracted accumulator\n     */\n    function sub(Accumulator memory a, Accumulator memory b) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: a.maker.sub(b.maker), taker: a.taker.sub(b.taker)});\n    }\n\n    /**\n     * @notice Multiplies two accumulators together\n     * @param a The first accumulator to multiply\n     * @param b The second accumulator to multiply\n     * @return The resulting multiplied accumulator\n     */\n    function mul(Accumulator memory a, Accumulator memory b) internal pure returns (Accumulator memory) {\n        return Accumulator({maker: a.maker.mul(b.maker), taker: a.taker.mul(b.taker)});\n    }\n\n    /**\n     * @notice Sums the maker and taker together from a single accumulator\n     * @param self The struct to operate on\n     * @return The sum of its maker and taker\n     */\n    function sum(Accumulator memory self) internal pure returns (Fixed18) {\n        return self.maker.add(self.taker);\n    }\n}\n"
    },
    "@equilibria/root/curve/CurveMath.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"../number/types/UFixed18.sol\";\nimport \"../number/types/Fixed18.sol\";\n\n/**\n * @title CurveMath\n * @notice Library for managing math operations for utilization curves.\n */\nlibrary CurveMath {\n    error CurveMathOutOfBoundsError();\n\n    /**\n     * @notice Computes a linear interpolation between two points\n     * @param startX First point's x-coordinate\n     * @param startY First point's y-coordinate\n     * @param endX Second point's x-coordinate\n     * @param endY Second point's y-coordinate\n     * @param targetX x-coordinate to interpolate\n     * @return y-coordinate for `targetX` along the line from (`startX`, `startY`) -> (`endX`, `endY`)\n     */\n    function linearInterpolation(\n        UFixed18 startX,\n        Fixed18 startY,\n        UFixed18 endX,\n        Fixed18 endY,\n        UFixed18 targetX\n    ) internal pure returns (Fixed18) {\n        if (targetX.lt(startX) || targetX.gt(endX)) revert CurveMathOutOfBoundsError();\n\n        UFixed18 xRange = endX.sub(startX);\n        Fixed18 yRange = endY.sub(startY);\n        UFixed18 xRatio = targetX.sub(startX).div(xRange);\n        return yRange.mul(Fixed18Lib.from(xRatio)).add(startY);\n    }\n}\n"
    },
    "@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"
    },
    "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"
    },
    "@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"
    },
    "@openzeppelin/contracts/proxy/beacon/IBeacon.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev This is the interface that {BeaconProxy} expects of its beacon.\n */\ninterface IBeacon {\n    /**\n     * @dev Must return an address that can be used as a delegate call target.\n     *\n     * {BeaconProxy} will check that this address is a contract.\n     */\n    function implementation() external view returns (address);\n}\n"
    },
    "contracts/interfaces/IIncentivizer.sol": {
      "content": "// SPDX-License-Identifier: Apache-2.0\npragma solidity ^0.8.13;\n\nimport \"@equilibria/root/token/types/Token18.sol\";\nimport \"@equilibria/root/number/types/UFixed18.sol\";\nimport \"@equilibria/perennial-oracle/contracts/interfaces/IOracleProvider.sol\";\nimport \"./types/ProgramInfo.sol\";\nimport \"./IController.sol\";\nimport \"./IProduct.sol\";\n\ninterface IIncentivizer {\n    event ProgramCreated(IProduct indexed product, uint256 indexed programId, ProgramInfo programInfo, UFixed18 programFeeAmount);\n    event ProgramStarted(IProduct indexed product, uint256 indexed programId, uint256 version);\n    event ProgramComplete(IProduct indexed product, uint256 indexed programId, uint256 version);\n    event Claim(IProduct indexed product, address indexed account, uint256 indexed programId, UFixed18 amount);\n    event FeeClaim(Token18 indexed token, UFixed18 amount);\n\n    error IncentivizerNotAllowedError(IProduct product);\n    error IncentivizerTooManyProgramsError();\n    error IncentivizerNotProgramOwnerError(IProduct product, uint256 programId);\n    error IncentivizerInvalidProgramError(IProduct product, uint256 programId);\n    error IncentivizerBatchClaimArgumentMismatchError();\n\n    function programInfos(IProduct product, uint256 programId) external view returns (ProgramInfo memory);\n    function fees(Token18 token) external view returns (UFixed18);\n    function initialize(IController controller_) external;\n    function create(IProduct product, ProgramInfo calldata info) external returns (uint256);\n    function complete(IProduct product, uint256 programId) external;\n    function sync(IOracleProvider.OracleVersion memory currentOracleVersion) external;\n    function syncAccount(address account, IOracleProvider.OracleVersion memory currentOracleVersion) external;\n    function claim(IProduct product, uint256[] calldata programIds) external;\n    function claim(IProduct[] calldata products, uint256[][] calldata programIds) external;\n    function claimFee(Token18[] calldata tokens) external;\n    function active(IProduct product) external view returns (uint256);\n    function count(IProduct product) external view returns (uint256);\n    function unclaimed(IProduct product, address account, uint256 programId) external view returns (UFixed18);\n    function available(IProduct product, uint256 programId) external view returns (UFixed18);\n    function versionStarted(IProduct product, uint256 programId) external view returns (uint256);\n    function versionComplete(IProduct product, uint256 programId) external view returns (uint256);\n    function owner(IProduct product, uint256 programId) external view returns (address);\n    function treasury(IProduct product, uint256 programId) external view returns (address);\n}\n"
    },
    "contracts/interfaces/types/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"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": false,
      "runs": 1000000
    },
    "outputSelection": {
      "*": {
        "*": [
          "storageLayout",
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
          "devdoc",
          "userdoc",
          "evm.gasEstimates"
        ],
        "": ["ast"]
      }
    },
    "metadata": {
      "useLiteralContent": true
    }
  }
}
